fix: add helpful error message when Python dependencies are missing (ACS-145) (#755)
* fix: add helpful error message when Python dependencies are missing When running runner scripts (spec_runner, insights_runner, etc.) without the virtual environment activated, users would get a cryptic ModuleNotFoundError for 'dotenv' or other dependencies. This fix adds a try-except around the dotenv import that provides a clear error message explaining: - The issue is likely due to not using the virtual environment - How to activate the venv (Linux/macOS/Windows) - How to install dependencies directly - Shows the current Python executable being used Also fixes CLI-USAGE.md which had incorrect paths for spec_runner.py (the file is in runners/, not the backend root). Related to: ACS-145 Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> * fix: improve error messages with explicit package name and requirements path - cli/utils.py: Explicitly mention 'python-dotenv' and add 'pip install python-dotenv' option - insights_runner.py: Use full path 'apps/backend/requirements.txt' for clarity Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> * refactor: centralize dotenv import error handling - Create shared import_dotenv() function in cli/utils.py - Update all runner scripts to use centralized function - Removes ~73 lines of duplicate code across 6 files - Ensures consistent error messaging (mentions python-dotenv explicitly) - Fixes path inconsistency in insights_runner.py Addresses CodeRabbit feedback about DRY principle violations. Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> * style: fix import ordering to satisfy ruff I001 rule Add blank lines to separate local imports and function calls from third-party imports, properly delineating import groups. Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> * style: auto-fix ruff I001 import ordering Ruff auto-fixed by adding blank line after 'from cli.utils import import_dotenv' to properly separate the import from the function call. Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> * style: apply ruff formatting to cli/utils.py - Add blank line after import statement - Use double quotes instead of single quotes Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> * refactor: return load_dotenv instead of mutating sys.modules - Change import_dotenv() to return load_dotenv callable - Remove sys.modules mutation for cleaner approach - Update callers to do: load_dotenv = import_dotenv() - Fixes ruff I001 import ordering violations - Preserves same error message on ImportError Addresses CodeRabbit feedback about import-order complexity. Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> --------- Signed-off-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Alex <63423455+AlexMadera@users.noreply.github.com>
This commit is contained in:
@@ -15,7 +15,46 @@ if str(_PARENT_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_PARENT_DIR))
|
||||
|
||||
from core.auth import get_auth_token, get_auth_token_source
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
||||
def import_dotenv():
|
||||
"""
|
||||
Import and return load_dotenv with helpful error message if not installed.
|
||||
|
||||
This centralized function ensures consistent error messaging across all
|
||||
runner scripts when python-dotenv is not available.
|
||||
|
||||
Returns:
|
||||
The load_dotenv function
|
||||
|
||||
Raises:
|
||||
SystemExit: If dotenv cannot be imported, with helpful installation instructions.
|
||||
"""
|
||||
try:
|
||||
from dotenv import load_dotenv as _load_dotenv
|
||||
|
||||
return _load_dotenv
|
||||
except ImportError:
|
||||
sys.exit(
|
||||
"Error: Required Python package 'python-dotenv' is not installed.\n"
|
||||
"\n"
|
||||
"This usually means you're not using the virtual environment.\n"
|
||||
"\n"
|
||||
"To fix this:\n"
|
||||
"1. From the 'apps/backend/' directory, activate the venv:\n"
|
||||
" source .venv/bin/activate # Linux/macOS\n"
|
||||
" .venv\\Scripts\\activate # Windows\n"
|
||||
"\n"
|
||||
"2. Or install dependencies directly:\n"
|
||||
" pip install python-dotenv\n"
|
||||
" pip install -r requirements.txt\n"
|
||||
"\n"
|
||||
f"Current Python: {sys.executable}\n"
|
||||
)
|
||||
|
||||
|
||||
# Load .env with helpful error if dependencies not installed
|
||||
load_dotenv = import_dotenv()
|
||||
from graphiti_config import get_graphiti_status
|
||||
from linear_integration import LinearManager
|
||||
from linear_updater import is_linear_enabled
|
||||
|
||||
@@ -56,8 +56,10 @@ if sys.platform == "win32":
|
||||
# Add backend to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
|
||||
# Load .env file
|
||||
from dotenv import load_dotenv
|
||||
# Load .env file with centralized error handling
|
||||
from cli.utils import import_dotenv
|
||||
|
||||
load_dotenv = import_dotenv()
|
||||
|
||||
env_file = Path(__file__).parent.parent.parent / ".env"
|
||||
if env_file.exists():
|
||||
|
||||
@@ -26,8 +26,10 @@ from pathlib import Path
|
||||
# Add backend to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||
|
||||
# Load .env file
|
||||
from dotenv import load_dotenv
|
||||
# Load .env file with centralized error handling
|
||||
from cli.utils import import_dotenv
|
||||
|
||||
load_dotenv = import_dotenv()
|
||||
|
||||
env_file = Path(__file__).parent.parent.parent / ".env"
|
||||
if env_file.exists():
|
||||
|
||||
@@ -26,8 +26,10 @@ from pathlib import Path
|
||||
# Add auto-claude to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
# Load .env file from auto-claude/ directory
|
||||
from dotenv import load_dotenv
|
||||
# Load .env file with centralized error handling
|
||||
from cli.utils import import_dotenv
|
||||
|
||||
load_dotenv = import_dotenv()
|
||||
|
||||
env_file = Path(__file__).parent.parent / ".env"
|
||||
if env_file.exists():
|
||||
|
||||
@@ -15,8 +15,10 @@ from pathlib import Path
|
||||
# Add auto-claude to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
# Load .env file from auto-claude/ directory
|
||||
from dotenv import load_dotenv
|
||||
# Load .env file with centralized error handling
|
||||
from cli.utils import import_dotenv
|
||||
|
||||
load_dotenv = import_dotenv()
|
||||
|
||||
env_file = Path(__file__).parent.parent / ".env"
|
||||
if env_file.exists():
|
||||
|
||||
@@ -20,8 +20,10 @@ from pathlib import Path
|
||||
# Add auto-claude to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
# Load .env file from auto-claude/ directory
|
||||
from dotenv import load_dotenv
|
||||
# Load .env file with centralized error handling
|
||||
from cli.utils import import_dotenv
|
||||
|
||||
load_dotenv = import_dotenv()
|
||||
|
||||
env_file = Path(__file__).parent.parent / ".env"
|
||||
if env_file.exists():
|
||||
|
||||
@@ -26,11 +26,11 @@ The AI considers:
|
||||
- Risk factors and edge cases
|
||||
|
||||
Usage:
|
||||
python auto-claude/spec_runner.py --task "Add user authentication"
|
||||
python auto-claude/spec_runner.py --interactive
|
||||
python auto-claude/spec_runner.py --continue 001-feature
|
||||
python auto-claude/spec_runner.py --task "Fix button color" --complexity simple
|
||||
python auto-claude/spec_runner.py --task "Simple fix" --no-ai-assessment
|
||||
python runners/spec_runner.py --task "Add user authentication"
|
||||
python runners/spec_runner.py --interactive
|
||||
python runners/spec_runner.py --continue 001-feature
|
||||
python runners/spec_runner.py --task "Fix button color" --complexity simple
|
||||
python runners/spec_runner.py --task "Simple fix" --no-ai-assessment
|
||||
"""
|
||||
|
||||
import sys
|
||||
@@ -81,8 +81,10 @@ if sys.platform == "win32":
|
||||
# Add auto-claude to path (parent of runners/)
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
# Load .env file
|
||||
from dotenv import load_dotenv
|
||||
# Load .env file with centralized error handling
|
||||
from cli.utils import import_dotenv
|
||||
|
||||
load_dotenv = import_dotenv()
|
||||
|
||||
env_file = Path(__file__).parent.parent / ".env"
|
||||
dev_env_file = Path(__file__).parent.parent.parent / "dev" / "auto-claude" / ".env"
|
||||
|
||||
+4
-4
@@ -74,16 +74,16 @@ All commands below should be run from the `apps/backend/` directory:
|
||||
source .venv/bin/activate
|
||||
|
||||
# Create a spec interactively
|
||||
python spec_runner.py --interactive
|
||||
python runners/spec_runner.py --interactive
|
||||
|
||||
# Or with a task description
|
||||
python spec_runner.py --task "Add user authentication with OAuth"
|
||||
python runners/spec_runner.py --task "Add user authentication with OAuth"
|
||||
|
||||
# Force a specific complexity level
|
||||
python spec_runner.py --task "Fix button color" --complexity simple
|
||||
python runners/spec_runner.py --task "Fix button color" --complexity simple
|
||||
|
||||
# Continue an interrupted spec
|
||||
python spec_runner.py --continue 001-feature
|
||||
python runners/spec_runner.py --continue 001-feature
|
||||
```
|
||||
|
||||
### Complexity Tiers
|
||||
|
||||
Reference in New Issue
Block a user