PyGuide

Learn Python with practical tutorials and code examples

Code Snippet Intermediate
• Updated Jan 15, 2025

Python Script Scheduling Fixes - Code Examples

Ready-to-use Python code snippets to fix scripts that work in terminal but fail when scheduled via cron or automation tools.

Python Script Scheduling Fixes - Code Examples

When your Python script works in terminal but not when scheduled, these ready-to-use code snippets will help you diagnose and fix the most common issues.

Complete Script Template for Scheduled Execution #

🐍 Try it yourself

Output:
Click "Run Code" to see the output

Environment Detection and Setup #

🐍 Try it yourself

Output:
Click "Run Code" to see the output

File Path Resolution Utilities #

import os
from pathlib import Path

class PathResolver:
    """Utility class for resolving file paths in scheduled scripts"""
    
    def __init__(self, script_file=__file__):
        self.script_path = Path(script_file).resolve()
        self.script_dir = self.script_path.parent
        self.project_root = self.find_project_root()
    
    def find_project_root(self):
        """Find project root by looking for common markers"""
        current = self.script_dir
        markers = ['.git', 'requirements.txt', 'setup.py', 'pyproject.toml']
        
        while current != current.parent:
            if any((current / marker).exists() for marker in markers):
                return current
            current = current.parent
        
        return self.script_dir  # Fallback to script directory
    
    def resolve_path(self, relative_path):
        """Resolve relative path from script directory"""
        return (self.script_dir / relative_path).resolve()
    
    def resolve_from_root(self, relative_path):
        """Resolve relative path from project root"""
        return (self.project_root / relative_path).resolve()
    
    def ensure_directory(self, path):
        """Ensure directory exists, create if necessary"""
        path = Path(path)
        path.mkdir(parents=True, exist_ok=True)
        return path

# Usage example
resolver = PathResolver()
config_file = resolver.resolve_path('config.json')
logs_dir = resolver.ensure_directory(resolver.resolve_path('logs'))

Configuration Management #

import json
import os
from pathlib import Path

class ConfigManager:
    """Manage configuration for scheduled scripts"""
    
    def __init__(self, config_file='script_config.json'):
        self.script_dir = Path(__file__).parent.absolute()
        self.config_file = self.script_dir / config_file
        self.config = self.load_config()
    
    def load_config(self):
        """Load configuration with fallback defaults"""
        default_config = {
            'python_executable': sys.executable,
            'working_directory': str(self.script_dir),
            'log_level': 'INFO',
            'log_file': 'script.log',
            'environment': {
                'PATH': '/usr/local/bin:/usr/bin:/bin',
                'PYTHONPATH': str(self.script_dir),
                'MPLBACKEND': 'Agg'
            },
            'email_notifications': {
                'enabled': False,
                'smtp_server': 'localhost',
                'recipients': []
            }
        }
        
        if self.config_file.exists():
            try:
                with open(self.config_file, 'r') as f:
                    user_config = json.load(f)
                    # Merge with defaults
                    default_config.update(user_config)
            except Exception as e:
                print(f"Error loading config: {e}, using defaults")
        
        return default_config
    
    def apply_environment(self):
        """Apply environment variables from configuration"""
        env_vars = self.config.get('environment', {})
        for key, value in env_vars.items():
            os.environ[key] = str(value)
    
    def get(self, key, default=None):
        """Get configuration value with dot notation support"""
        keys = key.split('.')
        value = self.config
        
        for k in keys:
            value = value.get(k, default)
            if value is None:
                break
        
        return value

# Usage
config = ConfigManager()
config.apply_environment()
log_level = config.get('log_level', 'INFO')

Cron-Safe Script Runner #

#!/usr/bin/env python3

import subprocess
import sys
import os
import logging
from pathlib import Path

def run_script_with_full_environment(script_path, python_executable=None):
    """Run a Python script with full environment setup"""
    
    if python_executable is None:
        python_executable = sys.executable
    
    # Build environment with common paths
    env = os.environ.copy()
    
    # Common system paths
    system_paths = [
        '/usr/local/bin',
        '/usr/bin',
        '/bin',
        '/usr/local/sbin',
        '/usr/sbin',
        '/sbin'
    ]
    
    # Add user paths if they exist
    user_paths = [
        os.path.expanduser('~/.local/bin'),
        os.path.expanduser('~/bin')
    ]
    
    # Python-specific paths
    python_paths = [
        os.path.dirname(python_executable),
        os.path.join(os.path.dirname(python_executable), 'Scripts')  # Windows
    ]
    
    all_paths = system_paths + user_paths + python_paths
    existing_paths = [p for p in all_paths if os.path.exists(p)]
    
    # Set comprehensive PATH
    env['PATH'] = ':'.join(existing_paths + [env.get('PATH', '')])
    
    # Set working directory to script location
    script_dir = os.path.dirname(os.path.abspath(script_path))
    
    # Run the script
    try:
        result = subprocess.run(
            [python_executable, script_path],
            cwd=script_dir,
            env=env,
            capture_output=True,
            text=True,
            timeout=3600  # 1 hour timeout
        )
        
        print(f"Exit code: {result.returncode}")
        if result.stdout:
            print(f"STDOUT:\n{result.stdout}")
        if result.stderr:
            print(f"STDERR:\n{result.stderr}")
        
        return result.returncode
        
    except subprocess.TimeoutExpired:
        print("Script timed out after 1 hour")
        return 124
    except Exception as e:
        print(f"Error running script: {e}")
        return 1

# Usage for cron
if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python cron_runner.py <script_path>")
        sys.exit(1)
    
    script_path = sys.argv[1]
    exit_code = run_script_with_full_environment(script_path)
    sys.exit(exit_code)

Summary #

These code snippets provide robust solutions for the most common issues when Python scripts work in terminal but fail when scheduled. The ScheduledScriptBase class offers a complete foundation for scheduled scripts, while the utility functions help with environment detection, path resolution, and configuration management.

Key features included:

  • Automatic environment setup and PATH configuration
  • Comprehensive logging with environment information
  • Robust error handling and recovery
  • Configuration management with sensible defaults
  • Cron-safe script execution wrapper

Use these snippets as building blocks to make your Python scripts reliable in any execution environment.

Related Snippets

Snippet Intermediate

Python Enumerate Zip: Ready-to-Use Code Examples

Copy-paste Python enumerate zip code snippets for combining multiple sequences with index tracking and parallel iteration.

#python #enumerate #zip +2
View Code
Syntax
Snippet Beginner

Python For Loop Counter Code Examples

Ready-to-use Python code snippets for implementing for loops with counters using enumerate(), range(), and custom counter patterns.

#python #for-loop #counter +2
View Code
Syntax
Snippet Beginner

Python Enumerate Start at 1: Code Examples and Snippets

Ready-to-use Python enumerate start at 1 code snippets for menus, lists, rankings, and user-friendly numbering systems.

#python #enumerate #start +2
View Code
Syntax
Snippet Beginner

Python For Loop Break: Ready-to-Use Code Examples

Copy-paste Python for loop break code snippets for search operations, early termination, and loop control in various scenarios.

#python #for-loop #break +2
View Code
Syntax