stredne pokročilý

Automatizačný skript

DeepSeek v3.2 prompt pre písanie Python skriptov na automatizáciu úloh s ošetrením chýb a logovaním

Programovanie
DeepSeek, ChatGPT, Claude
#deepseek#automation#python#script#programming

Automatizačný skript

DEEPSEEK v3.2 PROMPT

25. AUTOMATIZAČNÝ SKRIPT

Prompt: „Napíš Python skript, ktorý automatizuje úlohu [konkrétna úloha] s ošetrením chýb a logovaním."


ŠTRUKTÚRA AUTOMATIZAČNÉHO SKRIPTU

ZÁKLADNÉ KOMPONENTY

  • Configuration: Nastavenia a parametre
  • Main logic: Hlavná funkcionalita
  • Error handling: Ošetrenie chýb
  • Logging: Zaznamenávanie aktivít
  • CLI interface: Príkazový riadok
  • Testing: Testovacie funkcie

ŠTANDARDNÉ PRAKTIKY

  • Modular design: Modulárny dizajn
  • Configuration files: Konfiguračné súbory
  • Environment variables: Premenné prostredia
  • Graceful shutdown: Korektné ukončenie
  • Resource cleanup: Uvoľnenie zdrojov

PRÍKLAD: FILE AUTOMATION SKRIPT

úLOHA: Automatic file organizer

#!/usr/bin/env python3
"""
Automatic File Organizer Script

This script automatically organizes files in a specified directory
by moving them to appropriate subdirectories based on file type.

Author: Your Name
Version: 1.0.0
Date: 2024-01-15
"""

import os
import sys
import shutil
import logging
import argparse
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional
import json
import mimetypes

# Configuration
CONFIG_FILE = "file_organizer_config.json"
DEFAULT_CONFIG = {
    "source_directory": "~/Downloads",
    "target_directories": {
        "images": ["jpg", "jpeg", "png", "gif", "bmp", "svg", "webp"],
        "documents": ["pdf", "doc", "docx", "txt", "rtf", "odt", "xls", "xlsx", "ppt", "pptx"],
        "videos": ["mp4", "avi", "mkv", "mov", "wmv", "flv", "webm"],
        "audio": ["mp3", "wav", "flac", "aac", "ogg", "m4a"],
        "archives": ["zip", "rar", "7z", "tar", "gz", "bz2"],
        "code": ["py", "js", "html", "css", "java", "cpp", "c", "php", "rb"],
        "others": []
    },
    "log_level": "INFO",
    "dry_run": False,
    "create_directories": True,
    "backup_important": True
}

class FileOrganizer:
    """Automatic file organizer with error handling and logging."""

    def __init__(self, config_path: str = CONFIG_FILE):
        """Initialize the file organizer with configuration."""
        self.config = self._load_config(config_path)
        self._setup_logging()
        self.source_dir = Path(self.config["source_directory"]).expanduser()
        self.stats = {
            "processed": 0,
            "moved": 0,
            "errors": 0,
            "skipped": 0
        }

    def _load_config(self, config_path: str) -> Dict:
        """Load configuration from file or create default."""
        config_path = Path(config_path)

        if config_path.exists():
            try:
                with open(config_path, 'r', encoding='utf-8') as f:
                    user_config = json.load(f)
                # Merge with default config
                config = {**DEFAULT_CONFIG, **user_config}
                logging.info(f"Configuration loaded from {config_path}")
                return config
            except (json.JSONDecodeError, IOError) as e:
                logging.error(f"Error loading config file: {e}")
                logging.info("Using default configuration")
                return DEFAULT_CONFIG.copy()
        else:
            # Create default config file
            try:
                with open(config_path, 'w', encoding='utf-8') as f:
                    json.dump(DEFAULT_CONFIG, f, indent=2)
                logging.info(f"Created default config file at {config_path}")
            except IOError as e:
                logging.warning(f"Could not create config file: {e}")

            return DEFAULT_CONFIG.copy()

    def _setup_logging(self) -> None:
        """Setup logging configuration."""
        log_level = getattr(logging, self.config.get("log_level", "INFO"))

        # Create logs directory
        log_dir = Path("logs")
        log_dir.mkdir(exist_ok=True)

        # Setup file handler
        log_file = log_dir / f"file_organizer_{datetime.now().strftime('%Y%m%d')}.log"
        file_handler = logging.FileHandler(log_file)
        file_handler.setLevel(log_level)

        # Setup console handler
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)

        # Setup formatter
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        file_handler.setFormatter(formatter)
        console_handler.setFormatter(formatter)

        # Setup logger
        logger = logging.getLogger(__name__)
        logger.setLevel(log_level)
        logger.addHandler(file_handler)
        logger.addHandler(console_handler)

        self.logger = logger

    def _get_file_category(self, file_path: Path) -> str:
        """Determine the category for a file based on its extension."""
        extension = file_path.suffix.lower().lstrip('.')

        for category, extensions in self.config["target_directories"].items():
            if extension in extensions:
                return category

        # Try to determine from MIME type
        mime_type, _ = mimetypes.guess_type(str(file_path))
        if mime_type:
            if mime_type.startswith('image/'):
                return 'images'
            elif mime_type.startswith('video/'):
                return 'videos'
            elif mime_type.startswith('audio/'):
                return 'audio'
            elif mime_type.startswith('text/'):
                return 'documents'

        return 'others'

    def _create_target_directory(self, category: str) -> Path:
        """Create target directory if it doesn't exist."""
        target_dir = self.source_dir / category

        if self.config.get("create_directories", True):
            try:
                target_dir.mkdir(exist_ok=True)
                self.logger.debug(f"Ensured directory exists: {target_dir}")
            except OSError as e:
                self.logger.error(f"Failed to create directory {target_dir}: {e}")
                raise

        return target_dir

    def _backup_important_file(self, file_path: Path) -> Optional[Path]:
        """Create backup of important files before moving."""
        if not self.config.get("backup_important", False):
            return None

        # Define important file types
        important_extensions = {'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'}

        if file_path.suffix.lower().lstrip('.') in important_extensions:
            backup_dir = self.source_dir / "backups"
            backup_dir.mkdir(exist_ok=True)

            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            backup_name = f"{file_path.stem}_{timestamp}{file_path.suffix}"
            backup_path = backup_dir / backup_name

            try:
                shutil.copy2(file_path, backup_path)
                self.logger.info(f"Created backup: {backup_path}")
                return backup_path
            except OSError as e:
                self.logger.error(f"Failed to create backup for {file_path}: {e}")
                return None

        return None

    def _move_file(self, file_path: Path, target_dir: Path) -> bool:
        """Move a file to the target directory with error handling."""
        try:
            # Create backup if needed
            self._backup_important_file(file_path)

            # Handle name conflicts
            target_path = target_dir / file_path.name
            counter = 1

            while target_path.exists():
                stem = file_path.stem
                suffix = file_path.suffix
                target_path = target_dir / f"{stem}_{counter}{suffix}"
                counter += 1

            # Move the file
            shutil.move(str(file_path), str(target_path))
            self.logger.info(f"Moved: {file_path} -> {target_path}")
            self.stats["moved"] += 1

            return True

        except (OSError, shutil.Error) as e:
            self.logger.error(f"Failed to move {file_path}: {e}")
            self.stats["errors"] += 1
            return False

    def organize_files(self) -> Dict:
        """Main method to organize files in the source directory."""
        self.logger.info(f"Starting file organization in: {self.source_dir}")

        if not self.source_dir.exists():
            self.logger.error(f"Source directory does not exist: {self.source_dir}")
            raise FileNotFoundError(f"Source directory not found: {self.source_dir}")

        if not self.source_dir.is_dir():
            self.logger.error(f"Source path is not a directory: {self.source_dir}")
            raise NotADirectoryError(f"Source path is not a directory: {self.source_dir}")

        # Get all files in source directory
        try:
            all_items = list(self.source_dir.iterdir())
            files = [item for item in all_items if item.is_file()]

            self.logger.info(f"Found {len(files)} files to process")

        except OSError as e:
            self.logger.error(f"Failed to list directory contents: {e}")
            raise

        # Process each file
        for file_path in files:
            self.stats["processed"] += 1

            try:
                # Skip hidden files and system files
                if file_path.name.startswith('.'):
                    self.logger.debug(f"Skipping hidden file: {file_path}")
                    self.stats["skipped"] += 1
                    continue

                # Determine category
                category = self._get_file_category(file_path)
                target_dir = self._create_target_directory(category)

                # Move file (or simulate if dry run)
                if self.config.get("dry_run", False):
                    self.logger.info(f"[DRY RUN] Would move: {file_path} -> {target_dir / file_path.name}")
                else:
                    self._move_file(file_path, target_dir)

            except Exception as e:
                self.logger.error(f"Error processing {file_path}: {e}")
                self.stats["errors"] += 1
                continue

        # Log statistics
        self._log_statistics()

        return self.stats

    def _log_statistics(self) -> None:
        """Log organization statistics."""
        self.logger.info("File organization completed")
        self.logger.info(f"Files processed: {self.stats['processed']}")
        self.logger.info(f"Files moved: {self.stats['moved']}")
        self.logger.info(f"Files skipped: {self.stats['skipped']}")
        self.logger.info(f"Errors encountered: {self.stats['errors']}")

        if self.stats["errors"] > 0:
            self.logger.warning(f"Completed with {self.stats['errors']} errors")
        else:
            self.logger.info("Completed successfully without errors")

    def run_cleanup(self) -> None:
        """Clean up empty directories."""
        self.logger.info("Starting cleanup of empty directories")

        for category in self.config["target_directories"].keys():
            category_dir = self.source_dir / category

            if category_dir.exists() and category_dir.is_dir():
                try:
                    # Remove empty directories
                    for item in category_dir.iterdir():
                        if item.is_dir() and not any(item.iterdir()):
                            try:
                                item.rmdir()
                                self.logger.info(f"Removed empty directory: {item}")
                            except OSError as e:
                                self.logger.warning(f"Could not remove directory {item}: {e}")

                    # Check if category directory is empty
                    if not any(category_dir.iterdir()):
                        try:
                            category_dir.rmdir()
                            self.logger.info(f"Removed empty category directory: {category_dir}")
                        except OSError as e:
                            self.logger.warning(f"Could not remove category directory {category_dir}: {e}")

                except OSError as e:
                    self.logger.error(f"Error during cleanup of {category_dir}: {e}")


def create_parser() -> argparse.ArgumentParser:
    """Create command line argument parser."""
    parser = argparse.ArgumentParser(
        description="Automatic File Organizer - Organize files by type",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s                          # Run with default settings
  %(prog)s --source ~/Desktop       # Specify source directory
  %(prog)s --dry-run                 # Simulate without moving files
  %(prog)s --cleanup                  # Clean up empty directories
  %(prog)s --config custom.json     # Use custom configuration
        """
    )

    parser.add_argument(
        "--source", "-s",
        help="Source directory to organize (overrides config)",
        metavar="DIRECTORY"
    )

    parser.add_argument(
        "--dry-run", "-n",
        action="store_true",
        help="Simulate organization without moving files"
    )

    parser.add_argument(
        "--cleanup", "-c",
        action="store_true",
        help="Clean up empty directories after organizing"
    )

    parser.add_argument(
        "--config",
        help="Path to configuration file",
        default=CONFIG_FILE,
        metavar="FILE"
    )

    parser.add_argument(
        "--log-level",
        choices=["DEBUG", "INFO", "WARNING", "ERROR"],
        help="Set logging level",
        default="INFO"
    )

    parser.add_argument(
        "--version", "-v",
        action="version",
        version="File Organizer 1.0.0"
    )

    return parser


def main():
    """Main entry point for the script."""
    parser = create_parser()
    args = parser.parse_args()

    try:
        # Initialize organizer
        organizer = FileOrganizer(args.config)

        # Override config with command line arguments
        if args.source:
            organizer.config["source_directory"] = args.source

        if args.dry_run:
            organizer.config["dry_run"] = True

        if args.log_level:
            organizer.config["log_level"] = args.log_level
            organizer._setup_logging()

        # Run organization
        organizer.organize_files()

        # Run cleanup if requested
        if args.cleanup:
            organizer.run_cleanup()

        # Exit with appropriate code
        if organizer.stats["errors"] > 0:
            sys.exit(1)
        else:
            sys.exit(0)

    except KeyboardInterrupt:
        print("\nOperation cancelled by user")
        sys.exit(130)

    except FileNotFoundError as e:
        print(f"Error: {e}")
        sys.exit(1)

    except NotADirectoryError as e:
        print(f"Error: {e}")
        sys.exit(1)

    except Exception as e:
        print(f"Unexpected error: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()

USAGE EXAMPLES

# Basic usage
python file_organizer.py

# Specify source directory
python file_organizer.py --source ~/Downloads

# Dry run to see what would happen
python file_organizer.py --dry-run

# Clean up empty directories
python file_organizer.py --cleanup

# Custom configuration and log level
python file_organizer.py --config custom.json --log-level DEBUG

# Full example
python file_organizer.py --source ~/Downloads --dry-run --cleanup --log-level INFO

TESTOVACÍ SKRIPT

unit_tests.py

#!/usr/bin/env python3
"""
Unit tests for File Organizer
"""

import unittest
import tempfile
import shutil
from pathlib import Path
import json
import sys
import os

# Add the script directory to the path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from file_organizer import FileOrganizer


class TestFileOrganizer(unittest.TestCase):
    """Test cases for FileOrganizer class."""

    def setUp(self):
        """Set up test environment."""
        self.test_dir = Path(tempfile.mkdtemp())
        self.config_file = self.test_dir / "test_config.json"

        # Create test configuration
        self.test_config = {
            "source_directory": str(self.test_dir / "source"),
            "target_directories": {
                "images": ["jpg", "png"],
                "documents": ["pdf", "txt"],
                "others": []
            },
            "log_level": "DEBUG",
            "dry_run": False,
            "create_directories": True,
            "backup_important": False
        }

        # Write test config
        with open(self.config_file, 'w') as f:
            json.dump(self.test_config, f)

        # Create source directory and test files
        self.source_dir = self.test_dir / "source"
        self.source_dir.mkdir()

        # Create test files
        (self.source_dir / "test.jpg").touch()
        (self.source_dir / "document.pdf").touch()
        (self.source_dir / "unknown.xyz").touch()
        (self.source_dir / ".hidden").touch()

        # Initialize organizer
        self.organizer = FileOrganizer(str(self.config_file))

    def tearDown(self):
        """Clean up test environment."""
        shutil.rmtree(self.test_dir)

    def test_load_config(self):
        """Test configuration loading."""
        self.assertEqual(self.organizer.config["source_directory"], str(self.source_dir))
        self.assertIn("images", self.organizer.config["target_directories"])

    def test_get_file_category(self):
        """Test file category determination."""
        jpg_file = self.source_dir / "test.jpg"
        pdf_file = self.source_dir / "document.pdf"
        unknown_file = self.source_dir / "unknown.xyz"

        self.assertEqual(self.organizer._get_file_category(jpg_file), "images")
        self.assertEqual(self.organizer._get_file_category(pdf_file), "documents")
        self.assertEqual(self.organizer._get_file_category(unknown_file), "others")

    def test_create_target_directory(self):
        """Test target directory creation."""
        images_dir = self.organizer._create_target_directory("images")
        self.assertTrue(images_dir.exists())
        self.assertEqual(images_dir.name, "images")

    def test_organize_files(self):
        """Test file organization."""
        stats = self.organizer.organize_files()

        # Check statistics
        self.assertGreater(stats["processed"], 0)
        self.assertGreater(stats["moved"], 0)

        # Check if files were moved
        images_dir = self.source_dir / "images"
        documents_dir = self.source_dir / "documents"
        others_dir = self.source_dir / "others"

        self.assertTrue((images_dir / "test.jpg").exists())
        self.assertTrue((documents_dir / "document.pdf").exists())
        self.assertTrue((others_dir / "unknown.xyz").exists())

        # Hidden file should be skipped
        self.assertTrue((self.source_dir / ".hidden").exists())

    def test_dry_run(self):
        """Test dry run mode."""
        self.organizer.config["dry_run"] = True
        stats = self.organizer.organize_files()

        # Files should not be moved in dry run
        self.assertTrue((self.source_dir / "test.jpg").exists())
        self.assertTrue((self.source_dir / "document.pdf").exists())
        self.assertEqual(stats["moved"], 0)  # No files actually moved


class TestFileOrganizerEdgeCases(unittest.TestCase):
    """Test edge cases and error conditions."""

    def setUp(self):
        """Set up test environment."""
        self.test_dir = Path(tempfile.mkdtemp())
        self.config_file = self.test_dir / "test_config.json"

    def tearDown(self):
        """Clean up test environment."""
        shutil.rmtree(self.test_dir)

    def test_nonexistent_source_directory(self):
        """Test handling of nonexistent source directory."""
        config = {
            "source_directory": str(self.test_dir / "nonexistent"),
            "target_directories": {"images": ["jpg"]},
            "log_level": "ERROR"
        }

        with open(self.config_file, 'w') as f:
            json.dump(config, f)

        organizer = FileOrganizer(str(self.config_file))

        with self.assertRaises(FileNotFoundError):
            organizer.organize_files()

    def test_invalid_config_file(self):
        """Test handling of invalid configuration file."""
        # Create invalid JSON file
        with open(self.config_file, 'w') as f:
            f.write("invalid json content")

        # Should fall back to default configuration
        organizer = FileOrganizer(str(self.config_file))
        self.assertIn("images", organizer.config["target_directories"])


if __name__ == "__main__":
    unittest.main()

DEPLOYMENT A DISTRIBUTIA

setup.py

#!/usr/bin/env python3
"""
Setup script for File Organizer
"""

from setuptools import setup, find_packages
import os

# Read README file
def read_readme():
    with open("README.md", "r", encoding="utf-8") as fh:
        return fh.read()

# Read requirements
def read_requirements():
    with open("requirements.txt", "r", encoding="utf-8") as fh:
        return [line.strip() for line in fh if line.strip() and not line.startswith("#")]

setup(
    name="file-organizer",
    version="1.0.0",
    author="Your Name",
    author_email="your.email@example.com",
    description="Automatic file organizer with error handling and logging",
    long_description=read_readme(),
    long_description_content_type="text/markdown",
    url="https://github.com/yourusername/file-organizer",
    packages=find_packages(),
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "Intended Audience :: End Users/Desktop",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
        "Topic :: System :: Filesystems",
        "Topic :: Utilities",
    ],
    python_requires=">=3.7",
    install_requires=read_requirements(),
    entry_points={
        "console_scripts": [
            "file-organizer=file_organizer:main",
        ],
    },
    include_files=[
        "README.md",
        "LICENSE",
        "requirements.txt",
    ],
    zip_safe=False,
)

requirements.txt

# Core dependencies (Python 3.7+ standard library has most needed modules)
# No external dependencies required for basic functionality

# Optional dependencies for enhanced features
# watchdog>=2.1.0  # For file system monitoring
# schedule>=1.1.0    # For scheduled automation
# click>=8.0.0       # For enhanced CLI
# rich>=12.0.0       # For better terminal output

Dockerfile

FROM python:3.9-slim

WORKDIR /app

# Copy requirements and install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Create non-root user
RUN useradd --create-home --shell /bin/bash appuser
USER appuser

# Set entrypoint
ENTRYPOINT ["python", "file_organizer.py"]

# Default command
CMD ["--help"]

BEST PRACTICES

ERROR HANDLING STRATEGIES

🛡️ ROBUST ERROR HANDLING:
1. Validate inputs early
2. Use specific exception types
3. Log errors with context
4. Provide meaningful error messages
5. Graceful degradation
6. Resource cleanup in finally blocks

LOGGING BEST PRACTICES

📝 EFFECTIVE LOGGING:
1. Use appropriate log levels
2. Include context in log messages
3. Log both successes and failures
4. Use structured logging when possible
5. Rotate log files to prevent filling disk
6. Log sensitive data carefully

CONFIGURATION MANAGEMENT

⚙️ CONFIGURATION PRINCIPLES:
1. Separate code from configuration
2. Use environment variables for secrets
3. Provide sensible defaults
4. Validate configuration values
5. Document all configuration options
6. Support multiple config formats

SECURITY CONSIDERATIONS

🔒 SECURITY BEST PRACTICES:
1. Validate file paths to prevent directory traversal
2. Check file permissions before operations
3. Handle symlinks carefully
4. Limit file sizes to prevent DoS
5. Use secure temporary file handling
6. Sanitize user inputs

Podobné prompty

Programovanie

Ďalší prompt v kategórii

Preskúmajte ďalšie prompty v rovnakej kategórii.

Zobraziť viac →
Odporúčané

Najlepšie prompty

Objavte najpopulárnejšie a najúčinnejšie prompty.

Preskúmať všetky →