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 pathlib import Path
from typing import Optional
from shellhist.core import HistoryStore
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(
pattern: CommandPattern,
script_name: Optional[str] = None,
output_dir: str = ".",
patterns: list[CommandPattern],
script_name: str = "shellhist_script",
output_dir: Optional[str] = None,
dry_run: bool = False,
force: bool = False,
) -> tuple[str, str]:
"""Generate an executable shell script from a pattern.
) -> str:
"""Generate a shell script from detected patterns.
Args:
pattern: CommandPattern to generate script from.
script_name: Name for the script file.
output_dir: Directory to write script to.
dry_run: If True, return content without writing.
force: If True, overwrite existing files.
patterns: List of CommandPattern objects to export.
script_name: Name for the output script (without extension).
output_dir: Optional output directory. If not provided, uses current directory.
dry_run: If True, return script content without writing to file.
Returns:
Tuple of (script_path, content).
Path to the generated script or script content if dry_run.
"""
if script_name is None:
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,
)
script_content = _build_script_content(patterns, script_name)
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:
raise FileExistsError(f"Script already exists: {script_path}")
script_file = output_path / f"{script_name}.sh"
script_file.write_text(script_content, encoding="utf-8")
with open(script_path, "w", encoding="utf-8") as f:
f.write(content)
os.chmod(script_path, 0o755)
return script_path, content
return str(script_file)
def generate_script_name(pattern: CommandPattern) -> str:
"""Generate a script filename from a pattern.
def _build_script_content(patterns: list[CommandPattern], script_name: str) -> str:
"""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:
pattern: CommandPattern to generate name from.
for i, pattern in enumerate(patterns, 1):
if len(pattern.commands) == 1:
cmd = pattern.commands[0]
lines.append(f"# Pattern {i}: Command run {pattern.frequency} times")
lines.append(f"{cmd}")
else:
cmds = " && ".join(pattern.commands)
lines.append(f"# Pattern {i}: Sequence run {pattern.frequency} times")
lines.append(f"{cmds}")
lines.append("")
Returns:
Generated script filename.
"""
parts = []
for cmd in pattern.commands[:3]:
cmd_parts = cmd.split()
if cmd_parts:
base = os.path.basename(cmd_parts[0])
safe = "".join(c for c in base if c.isalnum() or c in "-_")
parts.append(safe[:10])
lines.extend([
"# End of generated script",
"echo 'Script execution completed.'",
])
name = "_".join(parts) if parts else "script"
return f"shellhist_{name}"
return "\n".join(lines)