# ============================================================================ # Python Project Template Functions # ============================================================================ # Quick project scaffolding with virtual environments # # Usage: # py-new # Create new Python project # py-django # Create Django project # py-flask # Create Flask project # py-fastapi # Create FastAPI project # py-data # Create data science project # py-cli # Create CLI tool project # ============================================================================ # Source shared colors (with fallback) source "${0:A:h}/../lib/colors.zsh" 2>/dev/null || \ source "$HOME/.dotfiles/zsh/lib/colors.zsh" 2>/dev/null || { typeset -g DF_GREEN=$'\033[0;32m' DF_BLUE=$'\033[0;34m' typeset -g DF_YELLOW=$'\033[1;33m' DF_CYAN=$'\033[0;36m' typeset -g DF_RED=$'\033[0;31m' DF_NC=$'\033[0m' } # ============================================================================ # Configuration # ============================================================================ typeset -g PY_TEMPLATE_BASE_DIR="${PY_TEMPLATE_BASE_DIR:-$HOME/projects}" typeset -g PY_TEMPLATE_PYTHON="${PY_TEMPLATE_PYTHON:-python3}" typeset -g PY_TEMPLATE_VENV_NAME="${PY_TEMPLATE_VENV_NAME:-venv}" typeset -g PY_TEMPLATE_USE_POETRY="${PY_TEMPLATE_USE_POETRY:-false}" typeset -g PY_TEMPLATE_GIT_INIT="${PY_TEMPLATE_GIT_INIT:-true}" # ============================================================================ # Helper Functions # ============================================================================ _py_print_step() { echo -e "${DF_BLUE}==>${DF_NC} $1" } _py_print_success() { echo -e "${DF_GREEN}✓${DF_NC} $1" } _py_print_info() { echo -e "${DF_CYAN}ℹ${DF_NC} $1" } _py_check_project_name() { local name="$1" if [[ -z "$name" ]]; then echo -e "${DF_YELLOW}⚠${DF_NC} Project name required" return 1 fi if [[ -d "$name" ]]; then echo -e "${DF_YELLOW}⚠${DF_NC} Directory '$name' already exists" return 1 fi return 0 } _py_create_venv() { local project_dir="$1" _py_print_step "Creating virtual environment" if [[ "$PY_TEMPLATE_USE_POETRY" == "true" ]] && command -v poetry &>/dev/null; then cd "$project_dir" poetry init --no-interaction poetry env use "$PY_TEMPLATE_PYTHON" _py_print_success "Poetry environment created" else "$PY_TEMPLATE_PYTHON" -m venv "$project_dir/$PY_TEMPLATE_VENV_NAME" _py_print_success "Virtual environment created: $PY_TEMPLATE_VENV_NAME" fi } _py_create_gitignore() { local project_dir="$1" cat > "$project_dir/.gitignore" << 'EOF' __pycache__/ *.py[cod] *$py.class *.so .Python build/ dist/ *.egg-info/ venv/ env/ .venv .vscode/ .idea/ *.swp .pytest_cache/ .coverage htmlcov/ .env *.log *.db *.sqlite3 .mypy_cache/ EOF _py_print_success "Created .gitignore" } _py_init_git() { local project_dir="$1" if [[ "$PY_TEMPLATE_GIT_INIT" == "true" ]]; then cd "$project_dir" git init git add . git commit -m "Initial commit: project scaffolding" _py_print_success "Git repository initialized" fi } _py_show_next_steps() { local project_name="$1" local has_venv="$2" echo echo -e "${DF_CYAN}Next steps:${DF_NC}" echo " cd $project_name" if [[ "$has_venv" == "true" ]]; then if [[ "$PY_TEMPLATE_USE_POETRY" == "true" ]]; then echo " poetry shell" else echo " source $PY_TEMPLATE_VENV_NAME/bin/activate" fi fi echo " # Start coding!" echo } # ============================================================================ # Base Python Project Template # ============================================================================ py-new() { local project_name="$1" _py_check_project_name "$project_name" || return 1 df_print_func_name "Python Project: $project_name" _py_print_step "Creating project structure" mkdir -p "$project_name"/{src,tests,docs} touch "$project_name/src/__init__.py" touch "$project_name/tests/__init__.py" cat > "$project_name/src/main.py" << 'EOF' #!/usr/bin/env python3 """Main module.""" def main(): print("Hello from Python!") if __name__ == "__main__": main() EOF cat > "$project_name/requirements.txt" << 'EOF' # Production dependencies # Development: pytest, black, flake8, mypy EOF _py_print_success "Project structure created" _py_create_venv "$project_name" _py_create_gitignore "$project_name" _py_init_git "$project_name" echo _py_print_success "Project '$project_name' created successfully!" _py_show_next_steps "$project_name" "true" } # ============================================================================ # Django Project Template # ============================================================================ py-django() { local project_name="$1" _py_check_project_name "$project_name" || return 1 df_print_func_name "Django Project: $project_name" mkdir -p "$project_name" _py_create_venv "$project_name" _py_print_step "Installing Django" cd "$project_name" "$PY_TEMPLATE_VENV_NAME/bin/pip" install django _py_print_step "Creating Django project structure" "$PY_TEMPLATE_VENV_NAME/bin/django-admin" startproject config . cat > "requirements.txt" << 'EOF' Django>=4.2.0 python-decouple>=3.8 EOF mkdir -p apps static templates media _py_create_gitignore "." _py_init_git "." cd .. echo _py_print_success "Django project '$project_name' created!" _py_show_next_steps "$project_name" "true" } # ============================================================================ # Flask Project Template # ============================================================================ py-flask() { local project_name="$1" _py_check_project_name "$project_name" || return 1 df_print_func_name "Flask Project: $project_name" mkdir -p "$project_name"/{app/{templates,static/{css,js}},tests} _py_create_venv "$project_name" cd "$project_name" _py_print_step "Installing Flask" "$PY_TEMPLATE_VENV_NAME/bin/pip" install flask cat > "app/__init__.py" << 'EOF' from flask import Flask def create_app(config=None): app = Flask(__name__) if config: app.config.from_object(config) from app.routes import main app.register_blueprint(main) return app EOF cat > "app/routes.py" << 'EOF' from flask import Blueprint, render_template main = Blueprint('main', __name__) @main.route('/') def index(): return render_template('index.html') EOF cat > "app.py" << 'EOF' #!/usr/bin/env python3 from app import create_app app = create_app() if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000) EOF chmod +x app.py cat > "app/templates/index.html" << 'EOF' Flask App

Welcome to Flask!

EOF cat > "requirements.txt" << 'EOF' Flask>=3.0.0 python-decouple>=3.8 EOF _py_create_gitignore "." _py_init_git "." cd .. echo _py_print_success "Flask project '$project_name' created!" _py_show_next_steps "$project_name" "true" } # ============================================================================ # FastAPI Project Template # ============================================================================ py-fastapi() { local project_name="$1" _py_check_project_name "$project_name" || return 1 df_print_func_name "FastAPI Project: $project_name" mkdir -p "$project_name"/{app/{api,models,schemas},tests} _py_create_venv "$project_name" cd "$project_name" _py_print_step "Installing FastAPI" "$PY_TEMPLATE_VENV_NAME/bin/pip" install fastapi uvicorn[standard] pydantic touch "app/__init__.py" cat > "app/main.py" << 'EOF' from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware app = FastAPI(title="My API", version="0.1.0") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) @app.get("/") def root(): return {"message": "Welcome to FastAPI"} @app.get("/health") def health(): return {"status": "healthy"} EOF cat > "run.py" << 'EOF' #!/usr/bin/env python3 import uvicorn if __name__ == "__main__": uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True) EOF chmod +x run.py cat > "requirements.txt" << 'EOF' fastapi>=0.104.0 uvicorn[standard]>=0.24.0 pydantic>=2.5.0 EOF _py_create_gitignore "." _py_init_git "." cd .. echo _py_print_success "FastAPI project '$project_name' created!" _py_print_info "Docs at: http://localhost:8000/docs" _py_show_next_steps "$project_name" "true" } # ============================================================================ # Data Science Project Template # ============================================================================ py-data() { local project_name="$1" _py_check_project_name "$project_name" || return 1 df_print_func_name "Data Science Project: $project_name" mkdir -p "$project_name"/{data/{raw,processed},notebooks,src,models,reports/figures} _py_create_venv "$project_name" cd "$project_name" _py_print_step "Installing data science packages" "$PY_TEMPLATE_VENV_NAME/bin/pip" install pandas numpy matplotlib seaborn jupyter touch "src/__init__.py" touch data/raw/.gitkeep data/processed/.gitkeep cat > "requirements.txt" << 'EOF' pandas>=2.1.0 numpy>=1.24.0 matplotlib>=3.8.0 seaborn>=0.13.0 jupyter>=1.0.0 scikit-learn>=1.3.0 EOF _py_create_gitignore "." cat >> ".gitignore" << 'EOF' *.pkl *.h5 *.parquet data/raw/* data/processed/* !data/raw/.gitkeep !data/processed/.gitkeep models/*.pkl .ipynb_checkpoints EOF _py_init_git "." cd .. echo _py_print_success "Data science project '$project_name' created!" _py_print_info "Start Jupyter: jupyter notebook" _py_show_next_steps "$project_name" "true" } # ============================================================================ # CLI Tool Project Template # ============================================================================ py-cli() { local project_name="$1" _py_check_project_name "$project_name" || return 1 df_print_func_name "CLI Tool Project: $project_name" mkdir -p "$project_name"/{src/$project_name,tests} _py_create_venv "$project_name" cd "$project_name" _py_print_step "Installing click" "$PY_TEMPLATE_VENV_NAME/bin/pip" install click cat > "src/$project_name/__init__.py" << 'EOF' __version__ = "0.1.0" EOF cat > "src/$project_name/cli.py" << 'EOF' #!/usr/bin/env python3 import click @click.group() @click.version_option() def cli(): """CLI tool - A command-line utility.""" pass @cli.command() @click.argument('name', default='World') def greet(name): """Greet someone.""" click.echo(f"Hello, {name}!") if __name__ == '__main__': cli() EOF cat > "setup.py" << EOF from setuptools import setup, find_packages setup( name="$project_name", version="0.1.0", packages=find_packages(where="src"), package_dir={"": "src"}, install_requires=["click>=8.0.0"], entry_points={"console_scripts": ["$project_name=$project_name.cli:cli"]}, ) EOF cat > "requirements.txt" << 'EOF' click>=8.1.0 EOF _py_create_gitignore "." _py_init_git "." cd .. echo _py_print_success "CLI tool project '$project_name' created!" _py_print_info "Install with: pip install -e $project_name" _py_show_next_steps "$project_name" "true" } # ============================================================================ # Aliases # ============================================================================ alias pynew='py-new' alias pydjango='py-django' alias pyflask='py-flask' alias pyfast='py-fastapi' alias pydata='py-data' alias pycli='py-cli' # Quick venv activation venv() { if [[ -d "venv" ]]; then source venv/bin/activate elif [[ -d ".venv" ]]; then source .venv/bin/activate elif [[ -d "env" ]]; then source env/bin/activate else echo "No virtual environment found (venv, .venv, or env)" return 1 fi }