Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 installer/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def update_claude_config():

# Load existing config or create new
if config_path.exists():
config = json.loads(config_path.read_text())
config = json.loads(config_path.read_text(encoding="utf-8"))
else:
config = {"mcpServers": {}}

Expand Down
2 changes: 1 addition & 1 deletion src/basic_memory/cli/commands/import_memory_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ async def process_memory_json(
read_task = progress.add_task("Reading memory.json...", total=None)

# First pass - collect entities and relations
with open(json_path) as f:
with open(json_path, encoding="utf-8") as f:
lines = f.readlines()
progress.update(read_task, total=len(lines))

Expand Down
2 changes: 1 addition & 1 deletion src/basic_memory/markdown/entity_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ async def parse_file(self, path: Path | str) -> EntityMarkdown:
absolute_path = self.base_path / path

# Parse frontmatter and content using python-frontmatter
file_content = absolute_path.read_text()
file_content = absolute_path.read_text(encoding="utf-8")
return await self.parse_file_content(absolute_path, file_content)

async def parse_file_content(self, absolute_path, file_content):
Expand Down
8 changes: 3 additions & 5 deletions src/basic_memory/sync/sync_service.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
"""Service for syncing files between filesystem and database."""

import os

from dataclasses import dataclass
from dataclasses import field
import time
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Dict, Optional, Set, Tuple
Expand All @@ -18,7 +17,6 @@
from basic_memory.repository import EntityRepository, RelationRepository
from basic_memory.services import EntityService, FileService
from basic_memory.services.search_service import SearchService
import time


@dataclass
Expand Down Expand Up @@ -237,7 +235,7 @@ async def sync_markdown_file(self, path: str, new: bool = True) -> Tuple[Optiona
logger.debug(f"Parsing markdown file, path: {path}, new: {new}")

file_path = self.entity_parser.base_path / path
file_content = file_path.read_text()
file_content = file_path.read_text(encoding="utf-8")
file_contains_frontmatter = has_frontmatter(file_content)

# entity markdown will always contain front matter, so it can be used up create/update the entity
Expand Down
6 changes: 3 additions & 3 deletions tests/api/test_resource_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import json
from datetime import datetime, timezone
from pathlib import Path

import pytest
from pathlib import Path

from basic_memory.schemas import EntityResponse

Expand Down Expand Up @@ -346,7 +346,7 @@ async def test_put_resource_new_file(client, test_config, entity_repository, sea
assert full_path.exists()

# Verify file content
file_content = full_path.read_text()
file_content = full_path.read_text(encoding="utf-8")
assert json.loads(file_content) == canvas_data

# Verify entity was created in DB
Expand Down Expand Up @@ -420,7 +420,7 @@ async def test_put_resource_update_existing(client, test_config, entity_reposito
assert response.status_code == 200

# Verify file was updated
updated_content = full_path.read_text()
updated_content = full_path.read_text(encoding="utf-8")
assert json.loads(updated_content) == updated_data

# Verify entity was updated
Expand Down
15 changes: 8 additions & 7 deletions tests/cli/test_import_chatgpt.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Tests for import_chatgpt command."""

import json

import pytest
from typer.testing import CliRunner

from basic_memory.cli.app import import_app, app
from basic_memory.cli.app import app, import_app
from basic_memory.cli.commands import import_chatgpt
from basic_memory.config import config
from basic_memory.markdown import EntityParser, MarkdownProcessor
Expand Down Expand Up @@ -144,7 +145,7 @@ def sample_conversation_with_hidden():
def sample_chatgpt_json(tmp_path, sample_conversation):
"""Create a sample ChatGPT JSON file."""
json_file = tmp_path / "conversations.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
json.dump([sample_conversation], f)
return json_file

Expand All @@ -167,7 +168,7 @@ async def test_process_chatgpt_json(tmp_path, sample_chatgpt_json):
assert conv_path.exists()

# Check content formatting
content = conv_path.read_text()
content = conv_path.read_text(encoding="utf-8")
assert "# Test Conversation" in content
assert "### User" in content
assert "Hello, this is a test message" in content
Expand All @@ -183,14 +184,14 @@ async def test_process_code_blocks(tmp_path, sample_conversation_with_code):

# Create test file
json_file = tmp_path / "code_test.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
json.dump([sample_conversation_with_code], f)

await import_chatgpt.process_chatgpt_json(json_file, tmp_path, processor)

# Check content
conv_path = tmp_path / "20250111-code-test.md"
content = conv_path.read_text()
content = conv_path.read_text(encoding="utf-8")
assert "```python" in content
assert "def hello():" in content
assert "```" in content
Expand All @@ -204,7 +205,7 @@ async def test_hidden_messages(tmp_path, sample_conversation_with_hidden):

# Create test file
json_file = tmp_path / "hidden_test.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
json.dump([sample_conversation_with_hidden], f)

results = await import_chatgpt.process_chatgpt_json(json_file, tmp_path, processor)
Expand All @@ -214,7 +215,7 @@ async def test_hidden_messages(tmp_path, sample_conversation_with_hidden):

# Check content
conv_path = tmp_path / "20250111-hidden-test.md"
content = conv_path.read_text()
content = conv_path.read_text(encoding="utf-8")
assert "Visible message" in content
assert "Hidden message" not in content

Expand Down
9 changes: 5 additions & 4 deletions tests/cli/test_import_claude_conversations.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Tests for import_claude command (chat conversations)."""

import json

import pytest
from typer.testing import CliRunner

Expand Down Expand Up @@ -44,7 +45,7 @@ def sample_conversation():
def sample_conversations_json(tmp_path, sample_conversation):
"""Create a sample conversations.json file."""
json_file = tmp_path / "conversations.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
json.dump([sample_conversation], f)
return json_file

Expand All @@ -65,7 +66,7 @@ async def test_process_chat_json(tmp_path, sample_conversations_json):
# Check conversation file
conv_path = tmp_path / "20250105-test-conversation.md"
assert conv_path.exists()
content = conv_path.read_text()
content = conv_path.read_text(encoding="utf-8")

# Check content formatting
assert "### Human" in content
Expand Down Expand Up @@ -156,7 +157,7 @@ def test_import_conversation_with_attachments(tmp_path):
}

json_file = tmp_path / "with_attachments.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
json.dump([conversation], f)

# Set up environment
Expand All @@ -168,7 +169,7 @@ def test_import_conversation_with_attachments(tmp_path):

# Check attachment formatting
conv_path = tmp_path / "conversations/20250105-test-with-attachments.md"
content = conv_path.read_text()
content = conv_path.read_text(encoding="utf-8")
assert "**Attachment: test.txt**" in content
assert "```" in content
assert "Test file content" in content
9 changes: 5 additions & 4 deletions tests/cli/test_import_claude_projects.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Tests for import_claude_projects command."""

import json

import pytest
from typer.testing import CliRunner

Expand Down Expand Up @@ -43,7 +44,7 @@ def sample_project():
def sample_projects_json(tmp_path, sample_project):
"""Create a sample projects.json file."""
json_file = tmp_path / "projects.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
json.dump([sample_project], f)
return json_file

Expand All @@ -70,14 +71,14 @@ async def test_process_projects_json(tmp_path, sample_projects_json):
# Check document files
doc1 = project_dir / "docs/test-document.md"
assert doc1.exists()
content1 = doc1.read_text()
content1 = doc1.read_text(encoding="utf-8")
assert "# Test Document" in content1
assert "This is test content" in content1

# Check prompt template
prompt = project_dir / "prompt-template.md"
assert prompt.exists()
prompt_content = prompt.read_text()
prompt_content = prompt.read_text(encoding="utf-8")
assert "# Test Prompt" in prompt_content
assert "This is a test prompt" in prompt_content

Expand Down Expand Up @@ -160,7 +161,7 @@ def test_import_project_without_prompt(tmp_path):
}

json_file = tmp_path / "no_prompt.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
json.dump([project], f)

# Set up environment
Expand Down
7 changes: 4 additions & 3 deletions tests/cli/test_import_memory_json.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Tests for import_memory_json command."""

import json

import pytest
from typer.testing import CliRunner

Expand Down Expand Up @@ -35,7 +36,7 @@ def sample_entities():
def sample_json_file(tmp_path, sample_entities):
"""Create a sample memory.json file."""
json_file = tmp_path / "memory.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
for entity in sample_entities:
f.write(json.dumps(entity) + "\n")
return json_file
Expand All @@ -55,7 +56,7 @@ async def test_process_memory_json(tmp_path, sample_json_file):
# Check file was created
entity_file = tmp_path / "test/test_entity.md"
assert entity_file.exists()
content = entity_file.read_text()
content = entity_file.read_text(encoding="utf-8")
assert "Test observation 1" in content
assert "Test observation 2" in content
assert "test_relation [[related_entity]]" in content
Expand Down Expand Up @@ -120,7 +121,7 @@ def test_import_json_command_handle_old_format(tmp_path):
]

json_file = tmp_path / "old_format.json"
with open(json_file, "w") as f:
with open(json_file, "w", encoding="utf-8") as f:
for item in old_format:
f.write(json.dumps(item) + "\n")

Expand Down
10 changes: 5 additions & 5 deletions tests/markdown/test_markdown_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

import pytest

from basic_memory.markdown.markdown_processor import MarkdownProcessor, DirtyFileError
from basic_memory.markdown.markdown_processor import DirtyFileError, MarkdownProcessor
from basic_memory.markdown.schemas import (
EntityMarkdown,
EntityFrontmatter,
EntityMarkdown,
Observation,
Relation,
)
Expand Down Expand Up @@ -41,7 +41,7 @@ async def test_write_new_minimal_file(markdown_processor: MarkdownProcessor, tmp
await markdown_processor.write_file(path, markdown)

# Read back and verify
content = path.read_text()
content = path.read_text(encoding="utf-8")
assert "---" in content # Has frontmatter
assert "type: note" in content
assert "permalink: test" in content
Expand Down Expand Up @@ -90,7 +90,7 @@ async def test_write_new_file_with_content(markdown_processor: MarkdownProcessor
await markdown_processor.write_file(path, markdown)

# Read back and verify
content = path.read_text()
content = path.read_text(encoding="utf-8")

# Check content preserved exactly
assert "# Custom Title" in content
Expand Down Expand Up @@ -169,7 +169,7 @@ async def test_dirty_file_detection(markdown_processor: MarkdownProcessor, tmp_p
checksum = await markdown_processor.write_file(path, initial)

# Modify file directly
path.write_text(path.read_text() + "\nModified!")
path.write_text(path.read_text(encoding="utf-8") + "\nModified!")

# Try to update with old checksum
update = EntityMarkdown(
Expand Down
8 changes: 4 additions & 4 deletions tests/mcp/test_tool_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async def test_create_canvas(app, test_config):
assert file_path.exists()

# Verify content is correct
content = json.loads(file_path.read_text())
content = json.loads(file_path.read_text(encoding="utf-8"))
assert content["nodes"] == nodes
assert content["edges"] == edges

Expand Down Expand Up @@ -81,7 +81,7 @@ async def test_create_canvas_with_extension(app, test_config):
assert file_path.exists()

# Verify content
content = json.loads(file_path.read_text())
content = json.loads(file_path.read_text(encoding="utf-8"))
assert content["nodes"] == nodes


Expand Down Expand Up @@ -134,7 +134,7 @@ async def test_update_existing_canvas(app, test_config):
assert "Updated: visualizations/update-test.canvas" in result

# Verify content was updated
content = json.loads(file_path.read_text())
content = json.loads(file_path.read_text(encoding="utf-8"))
assert content["nodes"] == updated_nodes
assert content["edges"] == updated_edges

Expand Down Expand Up @@ -252,7 +252,7 @@ async def test_create_canvas_complex_content(app, test_config):
assert file_path.exists()

# Verify content is correct with all complex structures
content = json.loads(file_path.read_text())
content = json.loads(file_path.read_text(encoding="utf-8"))
assert len(content["nodes"]) == 4
assert len(content["edges"]) == 2

Expand Down
4 changes: 2 additions & 2 deletions tests/sync/test_tmp_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,14 @@ async def test_rapid_atomic_writes(watch_service, test_config):
await asyncio.sleep(0.1)

# Read content to verify
content1 = final_path.read_text()
content1 = final_path.read_text(encoding="utf-8")
assert content1 == "First version"

# Simulate the second atomic write
tmp2_path.rename(final_path)

# Verify content was updated
content2 = final_path.read_text()
content2 = final_path.read_text(encoding="utf-8")
assert content2 == "Second version"

# Create a batch of changes that might arrive in mixed order
Expand Down
2 changes: 1 addition & 1 deletion tests/sync/test_watch_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async def test_write_status(watch_service):
await watch_service.write_status()

assert watch_service.status_path.exists()
data = json.loads(watch_service.status_path.read_text())
data = json.loads(watch_service.status_path.read_text(encoding="utf-8"))
assert not data["running"]
assert data["error_count"] == 0

Expand Down
Loading
Loading