Skip to content

Commit 4704445

Browse files
Adding fallback to crew settings (#3562)
* Adding fallback to crew settings * fix: resolve ruff and mypy issues in cli/config.py --------- Co-authored-by: Greyson Lalonde <[email protected]>
1 parent 0ee438c commit 4704445

File tree

1 file changed

+78
-13
lines changed

1 file changed

+78
-13
lines changed

src/crewai/cli/config.py

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import json
2+
import tempfile
3+
from logging import getLogger
24
from pathlib import Path
35

46
from pydantic import BaseModel, Field
@@ -12,8 +14,48 @@
1214
)
1315
from crewai.cli.shared.token_manager import TokenManager
1416

17+
logger = getLogger(__name__)
18+
1519
DEFAULT_CONFIG_PATH = Path.home() / ".config" / "crewai" / "settings.json"
1620

21+
22+
def get_writable_config_path() -> Path | None:
23+
"""
24+
Find a writable location for the config file with fallback options.
25+
26+
Tries in order:
27+
1. Default: ~/.config/crewai/settings.json
28+
2. Temp directory: /tmp/crewai_settings.json (or OS equivalent)
29+
3. Current directory: ./crewai_settings.json
30+
4. In-memory only (returns None)
31+
32+
Returns:
33+
Path object for writable config location, or None if no writable location found
34+
"""
35+
fallback_paths = [
36+
DEFAULT_CONFIG_PATH, # Default location
37+
Path(tempfile.gettempdir()) / "crewai_settings.json", # Temporary directory
38+
Path.cwd() / "crewai_settings.json", # Current working directory
39+
]
40+
41+
for config_path in fallback_paths:
42+
try:
43+
config_path.parent.mkdir(parents=True, exist_ok=True)
44+
test_file = config_path.parent / ".crewai_write_test"
45+
try:
46+
test_file.write_text("test")
47+
test_file.unlink() # Clean up test file
48+
logger.info(f"Using config path: {config_path}")
49+
return config_path
50+
except Exception: # noqa: S112
51+
continue
52+
53+
except Exception: # noqa: S112
54+
continue
55+
56+
return None
57+
58+
1759
# Settings that are related to the user's account
1860
USER_SETTINGS_KEYS = [
1961
"tool_repository_username",
@@ -93,16 +135,32 @@ class Settings(BaseModel):
93135
default=DEFAULT_CLI_SETTINGS["oauth2_domain"],
94136
)
95137

96-
def __init__(self, config_path: Path = DEFAULT_CONFIG_PATH, **data):
97-
"""Load Settings from config path"""
98-
config_path.parent.mkdir(parents=True, exist_ok=True)
138+
def __init__(self, config_path: Path | None = None, **data):
139+
"""Load Settings from config path with fallback support"""
140+
if config_path is None:
141+
config_path = get_writable_config_path()
142+
143+
# If config_path is None, we're in memory-only mode
144+
if config_path is None:
145+
merged_data = {**data}
146+
# Dummy path for memory-only mode
147+
super().__init__(config_path=Path("/dev/null"), **merged_data)
148+
return
149+
150+
try:
151+
config_path.parent.mkdir(parents=True, exist_ok=True)
152+
except Exception:
153+
merged_data = {**data}
154+
# Dummy path for memory-only mode
155+
super().__init__(config_path=Path("/dev/null"), **merged_data)
156+
return
99157

100158
file_data = {}
101159
if config_path.is_file():
102160
try:
103161
with config_path.open("r") as f:
104162
file_data = json.load(f)
105-
except json.JSONDecodeError:
163+
except Exception:
106164
file_data = {}
107165

108166
merged_data = {**file_data, **data}
@@ -122,15 +180,22 @@ def reset(self) -> None:
122180

123181
def dump(self) -> None:
124182
"""Save current settings to settings.json"""
125-
if self.config_path.is_file():
126-
with self.config_path.open("r") as f:
127-
existing_data = json.load(f)
128-
else:
129-
existing_data = {}
130-
131-
updated_data = {**existing_data, **self.model_dump(exclude_unset=True)}
132-
with self.config_path.open("w") as f:
133-
json.dump(updated_data, f, indent=4)
183+
if str(self.config_path) == "/dev/null":
184+
return
185+
186+
try:
187+
if self.config_path.is_file():
188+
with self.config_path.open("r") as f:
189+
existing_data = json.load(f)
190+
else:
191+
existing_data = {}
192+
193+
updated_data = {**existing_data, **self.model_dump(exclude_unset=True)}
194+
with self.config_path.open("w") as f:
195+
json.dump(updated_data, f, indent=4)
196+
197+
except Exception: # noqa: S110
198+
pass
134199

135200
def _reset_user_settings(self) -> None:
136201
"""Reset all user settings to default values"""

0 commit comments

Comments
 (0)