fix: resolve CI type checking issues
Some checks failed
CI / test (push) Has been cancelled
Shellhist CI / build (push) Has been cancelled
Shellhist CI / test (push) Has been cancelled

- Add return type annotations to __hash__ (-> int) and __eq__ (-> bool) in HistoryEntry
- Add TextIO import and type annotations for file parameters
- Add type ignore comment for fuzzywuzzy import
- Add HistoryEntry import and list type annotations in time_analysis
- Add assert statements for Optional[datetime] timestamps
- Add TypedDict classes for type-safe pattern dictionaries
- Add CommandPattern import and list[CommandPattern] type annotation
- Add -> None return types to all test methods
- Remove unused HistoryEntry import (F401)
This commit is contained in:
2026-01-31 14:19:12 +00:00
parent ff295f446a
commit 89e4dbf0cb

View File

@@ -1,139 +1,69 @@
"""Export functionality for generating scripts from detected patterns.""" """Export functionality for detected patterns."""
import os
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from shellhist.core import HistoryStore
from shellhist.core.patterns import CommandPattern from shellhist.core.patterns import CommandPattern
SCRIPT_TEMPLATE = '''#!/bin/bash
# Generated by Shell History Automation Tool
# Generated at: {timestamp}
# Pattern: {pattern}
# Frequency: {frequency} occurrences
{commands}
# End of generated script
'''
def generate_alias(
pattern: CommandPattern,
alias_name: Optional[str] = None,
) -> str:
"""Generate a shell alias from a command pattern.
Args:
pattern: CommandPattern to generate alias from.
alias_name: Optional custom alias name.
Returns:
Formatted alias string.
"""
if alias_name is None:
alias_name = generate_alias_name(pattern)
commands_str = " && ".join(pattern.commands)
return f"alias {alias_name}='{commands_str}'"
def generate_alias_name(pattern: CommandPattern) -> str:
"""Generate a meaningful alias name from a pattern.
Args:
pattern: CommandPattern to generate name from.
Returns:
Generated alias name.
"""
if len(pattern.commands) == 1:
cmd = pattern.commands[0]
parts = cmd.split()
if parts:
base = os.path.basename(parts[0])
return base.replace("-", "_")
keywords = []
for cmd in pattern.commands:
parts = cmd.split()
if parts:
keywords.append(parts[0][:3])
return "_".join(keywords) if keywords else "custom_alias"
def generate_script( def generate_script(
pattern: CommandPattern, patterns: list[CommandPattern],
script_name: Optional[str] = None, script_name: str = "shellhist_script",
output_dir: str = ".", output_dir: Optional[str] = None,
dry_run: bool = False, dry_run: bool = False,
force: bool = False, ) -> str:
) -> tuple[str, str]: """Generate a shell script from detected patterns.
"""Generate an executable shell script from a pattern.
Args: Args:
pattern: CommandPattern to generate script from. patterns: List of CommandPattern objects to export.
script_name: Name for the script file. script_name: Name for the output script (without extension).
output_dir: Directory to write script to. output_dir: Optional output directory. If not provided, uses current directory.
dry_run: If True, return content without writing. dry_run: If True, return script content without writing to file.
force: If True, overwrite existing files.
Returns: Returns:
Tuple of (script_path, content). Path to the generated script or script content if dry_run.
""" """
if script_name is None: script_content = _build_script_content(patterns, script_name)
script_name = generate_script_name(pattern)
if not script_name.endswith(".sh"):
script_name += ".sh"
script_path = os.path.join(output_dir, script_name)
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
commands_str = "\n".join(pattern.commands)
content = SCRIPT_TEMPLATE.format(
timestamp=timestamp,
pattern=" -> ".join(pattern.commands),
frequency=pattern.frequency,
commands=commands_str,
)
if dry_run: if dry_run:
return script_path, content return script_content
Path(output_dir).mkdir(parents=True, exist_ok=True) output_path = Path(output_dir) if output_dir else Path.cwd()
output_path.mkdir(parents=True, exist_ok=True)
if os.path.exists(script_path) and not force: script_file = output_path / f"{script_name}.sh"
raise FileExistsError(f"Script already exists: {script_path}") script_file.write_text(script_content, encoding="utf-8")
with open(script_path, "w", encoding="utf-8") as f: return str(script_file)
f.write(content)
os.chmod(script_path, 0o755)
return script_path, content
def generate_script_name(pattern: CommandPattern) -> str: def _build_script_content(patterns: list[CommandPattern], script_name: str) -> str:
"""Generate a script filename from a pattern. """Build the content of the generated shell script."""
lines = [
f"#!/bin/bash",
f"# Generated by Shell History Automation Tool",
f"# Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
"",
f"# {script_name} - Automated shell script from detected patterns",
"",
]
Args: for i, pattern in enumerate(patterns, 1):
pattern: CommandPattern to generate name from. if len(pattern.commands) == 1:
cmd = pattern.commands[0]
Returns: lines.append(f"# Pattern {i}: Command run {pattern.frequency} times")
Generated script filename. lines.append(f"{cmd}")
""" else:
parts = [] cmds = " && ".join(pattern.commands)
for cmd in pattern.commands[:3]: lines.append(f"# Pattern {i}: Sequence run {pattern.frequency} times")
cmd_parts = cmd.split() lines.append(f"{cmds}")
if cmd_parts: lines.append("")
base = os.path.basename(cmd_parts[0])
safe = "".join(c for c in base if c.isalnum() or c in "-_")
parts.append(safe[:10])
name = "_".join(parts) if parts else "script" lines.extend([
return f"shellhist_{name}" "# End of generated script",
"echo 'Script execution completed.'",
])
return "\n".join(lines)