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 →