Skip to content

Commit cad7019

Browse files
authored
fix: main project always recreated on project list command (#421)
1 parent 099c334 commit cad7019

File tree

3 files changed

+74
-14
lines changed

3 files changed

+74
-14
lines changed

src/basic_memory/config.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ class BasicMemoryConfig(BaseSettings):
6464
projects: Dict[str, str] = Field(
6565
default_factory=lambda: {
6666
"main": Path(os.getenv("BASIC_MEMORY_HOME", Path.home() / "basic-memory")).as_posix()
67-
},
67+
}
68+
if os.getenv("BASIC_MEMORY_HOME")
69+
else {},
6870
description="Mapping of project names to their filesystem paths",
6971
)
7072
default_project: str = Field(
@@ -192,15 +194,16 @@ def get_project_path(self, project_name: Optional[str] = None) -> Path: # pragm
192194

193195
def model_post_init(self, __context: Any) -> None:
194196
"""Ensure configuration is valid after initialization."""
195-
# Ensure main project exists
196-
if "main" not in self.projects: # pragma: no cover
197+
# Ensure at least one project exists; if none exist then create main
198+
if not self.projects: # pragma: no cover
197199
self.projects["main"] = (
198200
Path(os.getenv("BASIC_MEMORY_HOME", Path.home() / "basic-memory"))
199201
).as_posix()
200202

201-
# Ensure default project is valid
203+
# Ensure default project is valid (i.e. points to an existing project)
202204
if self.default_project not in self.projects: # pragma: no cover
203-
self.default_project = "main"
205+
# Set default to first available project
206+
self.default_project = next(iter(self.projects.keys()))
204207

205208
@property
206209
def app_database_path(self) -> Path:

test-int/cli/test_project_commands_integration.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,45 @@ def test_project_set_default(app_config, config_manager):
119119
for line in lines:
120120
if "another-project" in line:
121121
assert "[X]" in line
122+
123+
124+
def test_remove_main_project(app_config, config_manager):
125+
"""Test that removing main project then listing projects prevents main from reappearing (issue #397)."""
126+
runner = CliRunner()
127+
128+
# Create separate temp dirs for each project
129+
with (
130+
tempfile.TemporaryDirectory() as main_dir,
131+
tempfile.TemporaryDirectory() as new_default_dir,
132+
):
133+
main_path = Path(main_dir)
134+
new_default_path = Path(new_default_dir)
135+
136+
# Ensure main exists
137+
result = runner.invoke(app, ["project", "list"])
138+
if "main" not in result.stdout:
139+
result = runner.invoke(app, ["project", "add", "main", str(main_path)])
140+
print(result.stdout)
141+
assert result.exit_code == 0
142+
143+
# Confirm main is present
144+
result = runner.invoke(app, ["project", "list"])
145+
assert "main" in result.stdout
146+
147+
# Add a second project
148+
result = runner.invoke(app, ["project", "add", "new_default", str(new_default_path)])
149+
assert result.exit_code == 0
150+
151+
# Set new_default as default (if needed)
152+
result = runner.invoke(app, ["project", "default", "new_default"])
153+
assert result.exit_code == 0
154+
155+
# Remove main
156+
result = runner.invoke(app, ["project", "remove", "main"])
157+
assert result.exit_code == 0
158+
159+
# Confirm only new_default exists and main does not
160+
result = runner.invoke(app, ["project", "list"])
161+
assert result.exit_code == 0
162+
assert "main" not in result.stdout
163+
assert "new_default" in result.stdout

tests/test_config.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,47 @@ def test_respects_basic_memory_home_environment_variable(self, config_home, monk
3232
# Should use the custom path from environment variable
3333
assert config.projects["main"] == custom_path
3434

35-
def test_model_post_init_respects_basic_memory_home(self, config_home, monkeypatch):
36-
"""Test that model_post_init creates main project with BASIC_MEMORY_HOME when missing."""
35+
def test_model_post_init_respects_basic_memory_home_creates_main(
36+
self, config_home, monkeypatch
37+
):
38+
"""Test that model_post_init creates main project with BASIC_MEMORY_HOME when missing and no other projects."""
3739
custom_path = str(config_home / "custom" / "memory" / "path")
3840
monkeypatch.setenv("BASIC_MEMORY_HOME", custom_path)
3941

4042
# Create config without main project
41-
other_path = str(config_home / "some" / "path")
42-
config = BasicMemoryConfig(projects={"other": other_path})
43+
config = BasicMemoryConfig()
4344

4445
# model_post_init should have added main project with BASIC_MEMORY_HOME
4546
assert "main" in config.projects
4647
assert config.projects["main"] == Path(custom_path).as_posix()
4748

49+
def test_model_post_init_respects_basic_memory_home_sets_non_main_default(
50+
self, config_home, monkeypatch
51+
):
52+
"""Test that model_post_init does not create main project with BASIC_MEMORY_HOME when another project exists."""
53+
custom_path = str(config_home / "custom" / "memory" / "path")
54+
monkeypatch.setenv("BASIC_MEMORY_HOME", custom_path)
55+
56+
# Create config without main project
57+
other_path = str(config_home / "some" / "path")
58+
config = BasicMemoryConfig(projects={"other": Path(other_path).as_posix()})
59+
60+
# model_post_init should not add main project with BASIC_MEMORY_HOME
61+
assert "main" not in config.projects
62+
assert config.projects["other"] == Path(other_path).as_posix()
63+
4864
def test_model_post_init_fallback_without_basic_memory_home(self, config_home, monkeypatch):
49-
"""Test that model_post_init falls back to default when BASIC_MEMORY_HOME is not set."""
65+
"""Test that model_post_init can set a non-main default when BASIC_MEMORY_HOME is not set."""
5066
# Ensure BASIC_MEMORY_HOME is not set
5167
monkeypatch.delenv("BASIC_MEMORY_HOME", raising=False)
5268

5369
# Create config without main project
5470
other_path = (config_home / "some" / "path").as_posix()
5571
config = BasicMemoryConfig(projects={"other": other_path})
5672

57-
# model_post_init should have added main project with default path
58-
expected_path = (config_home / "basic-memory").as_posix()
59-
assert "main" in config.projects
60-
assert config.projects["main"] == Path(expected_path).as_posix()
73+
# model_post_init should not add main project, but "other" should now be the default
74+
assert "main" not in config.projects
75+
assert config.projects["other"] == Path(other_path).as_posix()
6176

6277
def test_basic_memory_home_with_relative_path(self, config_home, monkeypatch):
6378
"""Test that BASIC_MEMORY_HOME works with relative paths."""

0 commit comments

Comments
 (0)