mirror of
https://github.com/MLSysBook/TinyTorch.git
synced 2026-05-31 13:40:52 -05:00
Feat(env) dynamic virtual env support for advanced users
This commit is contained in:
12
.envrc
12
.envrc
@@ -1,20 +1,24 @@
|
||||
# Python Virtual Environment Auto-Activation Template
|
||||
# Copy this file as .envrc to any Python project directory
|
||||
# Default usage:
|
||||
# Then run: direnv allow
|
||||
VENV_PATH=$(python -c "import json; print(json.load(open('.tinyrc')).get('venv_path', '.venv'))")
|
||||
echo "Using virtual env in ${VENV_PATH}"
|
||||
export VENV_PATH
|
||||
|
||||
# Check if .venv exists, create if it doesn't
|
||||
if [[ ! -d ".venv" ]]; then
|
||||
if [[ ! -d "$VENV_PATH" ]]; then
|
||||
echo "🔧 Creating Python virtual environment..."
|
||||
python3 -m venv .venv
|
||||
python3 -m venv "$VENV_PATH"
|
||||
echo "📦 Installing basic dependencies..."
|
||||
source .venv/bin/activate
|
||||
source "$VENV_PATH/bin/activate"
|
||||
pip install --upgrade pip
|
||||
# Uncomment the next line if you have a requirements.txt
|
||||
# pip install -r requirements.txt
|
||||
fi
|
||||
|
||||
# Activate the virtual environment
|
||||
source .venv/bin/activate
|
||||
source "$VENV_PATH/bin/activate"
|
||||
|
||||
# Set common Python environment variables
|
||||
export PYTHONPATH="${PWD}:${PYTHONPATH}"
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#!/bin/bash
|
||||
# Tiny🔥Torch Environment Activation & Setup
|
||||
|
||||
# Allow users to pass a path to existing virtual env
|
||||
VENV_PATH=${1:-".venv"}
|
||||
export VENV_PATH
|
||||
|
||||
# Check if virtual environment exists, create if not
|
||||
if [ ! -d ".venv" ]; then
|
||||
if [ ! -d "$VENV_PATH" ]; then
|
||||
echo "🆕 First time setup - creating environment..."
|
||||
python3 -m venv .venv || {
|
||||
python3 -m venv "$VENV_PATH" || {
|
||||
echo "❌ Failed to create virtual environment"
|
||||
exit 1
|
||||
}
|
||||
@@ -17,7 +21,7 @@ if [ ! -d ".venv" ]; then
|
||||
fi
|
||||
|
||||
echo "🔥 Activating Tiny🔥Torch environment..."
|
||||
source .venv/bin/activate
|
||||
source "$VENV_PATH/bin/activate"
|
||||
|
||||
# Create tito alias for convenience
|
||||
alias tito="python3 bin/tito"
|
||||
|
||||
@@ -5,9 +5,11 @@ Base command class for TinyTorch CLI.
|
||||
from abc import ABC, abstractmethod
|
||||
from argparse import ArgumentParser, Namespace
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
import logging
|
||||
|
||||
from ..core.config import CLIConfig
|
||||
from ..core.virtual_env_manager import get_venv_path
|
||||
from ..core.console import get_console
|
||||
from ..core.exceptions import TinyTorchCLIError
|
||||
|
||||
@@ -26,6 +28,11 @@ class BaseCommand(ABC):
|
||||
def name(self) -> str:
|
||||
"""Return the command name."""
|
||||
pass
|
||||
|
||||
@property
|
||||
def venv_path(self) -> Path:
|
||||
"""Return the command name."""
|
||||
return get_venv_path()
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
|
||||
@@ -41,8 +41,7 @@ class DoctorCommand(BaseCommand):
|
||||
env_table.add_row("Python", "[green]✅ OK[/green]", f"{sys.version.split()[0]} ({sys.platform})")
|
||||
|
||||
# Virtual environment - check if it exists and if we're using it
|
||||
venv_path = Path(".venv")
|
||||
venv_exists = venv_path.exists()
|
||||
venv_exists = self.venv_path.exists()
|
||||
in_venv = (
|
||||
# Method 1: Check VIRTUAL_ENV environment variable (most reliable for activation)
|
||||
os.environ.get('VIRTUAL_ENV') is not None or
|
||||
@@ -58,7 +57,7 @@ class DoctorCommand(BaseCommand):
|
||||
venv_status = "[yellow]✅ Ready (Not Active)[/yellow]"
|
||||
else:
|
||||
venv_status = "[red]❌ Not Found[/red]"
|
||||
env_table.add_row("Virtual Environment", venv_status, ".venv")
|
||||
env_table.add_row("Virtual Environment", venv_status, f"{self.venv_path}")
|
||||
|
||||
# Dependencies
|
||||
dependencies = [
|
||||
|
||||
@@ -478,7 +478,7 @@ class ExportCommand(BaseCommand):
|
||||
|
||||
# Get the project root directory (where .venv should be)
|
||||
project_root = Path(__file__).parent.parent.parent
|
||||
venv_jupytext = project_root / ".venv" / "bin" / "jupytext"
|
||||
venv_jupytext = self.venv_path / "bin" / "jupytext"
|
||||
|
||||
if venv_jupytext.exists():
|
||||
# Test venv jupytext first
|
||||
|
||||
@@ -409,8 +409,8 @@ class HelpCommand(BaseCommand):
|
||||
"```bash\n"
|
||||
"git clone https://github.com/mlsysbook/TinyTorch.git\n"
|
||||
"cd TinyTorch\n"
|
||||
"python -m venv .venv\n"
|
||||
"source .venv/bin/activate # Windows: .venv\\Scripts\\activate\n"
|
||||
f"python -m venv {self.venv_path}\n"
|
||||
f"source {self.venv_path}/bin/activate # Windows: .venv\\Scripts\\activate\n"
|
||||
"pip install -r requirements.txt\n"
|
||||
"pip install -e .\n"
|
||||
"```",
|
||||
|
||||
@@ -3,7 +3,6 @@ Info command for TinyTorch CLI: shows system information and course navigation.
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser, Namespace
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import os
|
||||
from rich.console import Console
|
||||
@@ -39,8 +38,7 @@ class InfoCommand(BaseCommand):
|
||||
info_text.append(f"Working Directory: {os.getcwd()}\n", style="cyan")
|
||||
|
||||
# Virtual environment check
|
||||
venv_path = Path(".venv")
|
||||
venv_exists = venv_path.exists()
|
||||
venv_exists = self.venv_path.exists()
|
||||
in_venv = (
|
||||
os.environ.get('VIRTUAL_ENV') is not None or
|
||||
(hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix) or
|
||||
|
||||
@@ -194,6 +194,7 @@ echo "✅ No auto-generated files being committed"
|
||||
vscode_dir = Path(".vscode")
|
||||
vscode_dir.mkdir(exist_ok=True)
|
||||
|
||||
python_default_interpreter = str(self.venv_path) + "/bin/python"
|
||||
vscode_settings = {
|
||||
"_comment_protection": "🛡️ TinyTorch Student Protection",
|
||||
"files.readonlyInclude": {
|
||||
@@ -204,7 +205,7 @@ echo "✅ No auto-generated files being committed"
|
||||
"files.decorations.badges": True,
|
||||
"explorer.decorations.colors": True,
|
||||
"explorer.decorations.badges": True,
|
||||
"python.defaultInterpreterPath": "./.venv/bin/python",
|
||||
"python.defaultInterpreterPath": python_default_interpreter,
|
||||
"python.terminal.activateEnvironment": True
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from pathlib import Path
|
||||
from typing import Dict, Any, Optional, List
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class CLIConfig:
|
||||
"""Configuration for TinyTorch CLI."""
|
||||
@@ -55,7 +56,7 @@ class CLIConfig:
|
||||
bin_dir=project_root / 'bin'
|
||||
)
|
||||
|
||||
def validate(self) -> List[str]:
|
||||
def validate(self, venv_path=Optional[Path]) -> List[str]:
|
||||
"""Validate the configuration and return any issues."""
|
||||
issues = []
|
||||
|
||||
@@ -73,10 +74,10 @@ class CLIConfig:
|
||||
# Method 3: Check for sys.real_prefix (older Python versions)
|
||||
hasattr(sys, 'real_prefix') or
|
||||
# Method 4: Check if .venv directory exists and packages are available
|
||||
(Path('.venv').exists() and self._packages_available())
|
||||
(venv_path.exists() and self._packages_available())
|
||||
)
|
||||
if not in_venv:
|
||||
issues.append("Virtual environment not activated. Run: source .venv/bin/activate")
|
||||
issues.append(f"Virtual environment not activated. Run: source {venv_path}/bin/activate")
|
||||
|
||||
# Check required directories
|
||||
if not self.assignments_dir.exists():
|
||||
|
||||
23
tito/core/virtual_env_manager.py
Normal file
23
tito/core/virtual_env_manager.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import os, json
|
||||
from pathlib import Path
|
||||
|
||||
DEFAULT_VENV = ".venv"
|
||||
CONFIG_FILE = ".tinyrc"
|
||||
|
||||
|
||||
def get_venv_path() -> Path:
|
||||
"""
|
||||
Fetch venv in case users have a custom path
|
||||
"""
|
||||
print(f"running this from {os.getcwd()}")
|
||||
if "VENV_PATH" in os.environ:
|
||||
return Path(os.environ["VENV_PATH"]).expanduser().resolve()
|
||||
|
||||
if Path(CONFIG_FILE).exists():
|
||||
try:
|
||||
cfg = json.load(open(CONFIG_FILE))
|
||||
return Path(cfg.get("venv_path", DEFAULT_VENV)).expanduser().resolve()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return Path(DEFAULT_VENV).resolve()
|
||||
@@ -17,6 +17,7 @@ from pathlib import Path
|
||||
from typing import Dict, Type, Optional, List
|
||||
|
||||
from .core.config import CLIConfig
|
||||
from .core.virtual_env_manager import get_venv_path
|
||||
from .core.console import get_console, print_banner, print_error, print_ascii_logo
|
||||
from .core.exceptions import TinyTorchCLIError
|
||||
from rich.panel import Panel
|
||||
@@ -158,7 +159,7 @@ Examples:
|
||||
|
||||
def validate_environment(self) -> bool:
|
||||
"""Validate the environment and show issues if any."""
|
||||
issues = self.config.validate()
|
||||
issues = self.config.validate(get_venv_path())
|
||||
|
||||
if issues:
|
||||
print_error(
|
||||
|
||||
Reference in New Issue
Block a user