"""本地工具运行器 - 替代 Docker 调用""" import subprocess import logging from pathlib import Path from typing import Dict, Any import os logger = logging.getLogger(__name__) class ToolRunner: """本地工具运行管理器""" def run_bttoxin_digger( self, input_dir: Path, output_dir: Path, sequence_type: str = "nucl", scaf_suffix: str = ".fna", threads: int = 4 ) -> Dict[str, Any]: """ 在本地环境运行 BtToxin_Digger 使用 'pixi run -e digger' 激活环境 """ # Ensure output directory exists output_dir.mkdir(parents=True, exist_ok=True) # BtToxin_Digger expects to read files from --SeqPath. # It scans the directory for files matching *suffix. # We point it to the input directory. seq_path = input_dir.absolute() # Construct command # Note: We run this from output_dir so 'Results/' are created there. command = [ "pixi", "run", "-e", "digger", "BtToxin_Digger", "--SeqPath", str(seq_path), "--SequenceType", sequence_type, "--Scaf_suffix", scaf_suffix, "--threads", str(threads) ] logger.info(f"Running command: {' '.join(command)}") logger.info(f"Working directory: {output_dir}") try: # Run subprocess # Capture both stdout and stderr process = subprocess.run( command, cwd=str(output_dir), capture_output=True, text=True, check=False, env=os.environ.copy() # Inherit env vars (PATH, etc) ) success = (process.returncode == 0) logs = f"STDOUT:\n{process.stdout}\n\nSTDERR:\n{process.stderr}" if not success: logger.error(f"BtToxin_Digger failed with exit code {process.returncode}") logger.error(process.stderr) return { 'success': success, 'logs': logs, 'exit_code': process.returncode } except Exception as e: logger.error(f"Execution error: {e}") return {'success': False, 'error': str(e)}