fix: resolve CI type checking issues
Some checks failed
CI / test (push) Has been cancelled
Shellhist CI / test (push) Has been cancelled
Shellhist CI / build (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:20 +00:00
parent 7028371275
commit a025fd4956

View File

@@ -8,7 +8,7 @@ import click
from rich.console import Console
from rich.table import Table
from shellhist.core import HistoryLoader
from shellhist.core import HistoryLoader, HistoryEntry
@click.command("analyze-time")
@@ -84,7 +84,7 @@ def analyze_time_command(
cutoff = _parse_time_range(time_range)
recent_entries = [
e for e in entries_with_time
if e.timestamp >= cutoff
if e.timestamp is not None and e.timestamp >= cutoff
]
if daily:
@@ -119,11 +119,12 @@ def _parse_time_range(time_range: str) -> datetime:
return now - timedelta(days=7)
def _analyze_hourly_distribution(console: Console, entries: list) -> None:
def _analyze_hourly_distribution(console: Console, entries: list[HistoryEntry]) -> None:
"""Analyze command distribution by hour of day."""
hourly = defaultdict(list)
hourly: dict[int, list[str]] = defaultdict(list)
for entry in entries:
assert entry.timestamp is not None
hour = entry.timestamp.hour
hourly[hour].append(entry.command)
@@ -137,7 +138,7 @@ def _analyze_hourly_distribution(console: Console, entries: list) -> None:
for hour in range(24):
cmds = hourly.get(hour, [])
if cmds:
top = defaultdict(int)
top: dict[str, int] = defaultdict(int)
for cmd in cmds:
top[cmd] += 1
top_sorted = sorted(top.items(), key=lambda x: x[1], reverse=True)[:2]
@@ -151,11 +152,12 @@ def _analyze_hourly_distribution(console: Console, entries: list) -> None:
console.print(table)
def _analyze_daily_patterns(console: Console, entries: list) -> None:
def _analyze_daily_patterns(console: Console, entries: list[HistoryEntry]) -> None:
"""Analyze commands run at similar times daily."""
daily_patterns = defaultdict(list)
daily_patterns: dict[tuple[int, int], list[str]] = defaultdict(list)
for entry in entries:
assert entry.timestamp is not None
hour = entry.timestamp.hour
key = (entry.timestamp.weekday(), hour)
daily_patterns[key].append(entry.command)
@@ -164,10 +166,18 @@ def _analyze_daily_patterns(console: Console, entries: list) -> None:
day_names = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
patterns_found = []
from typing import TypedDict
class DailyPattern(TypedDict):
day: str
hour: int
count: int
top: list[tuple[str, int]]
patterns_found: list[DailyPattern] = []
for (weekday, hour), cmds in daily_patterns.items():
if len(cmds) >= 2:
top = defaultdict(int)
top: dict[str, int] = defaultdict(int)
for cmd in cmds:
top[cmd] += 1
top_sorted = sorted(top.items(), key=lambda x: x[1], reverse=True)[:3]
@@ -202,11 +212,12 @@ def _analyze_daily_patterns(console: Console, entries: list) -> None:
console.print(table)
def _analyze_weekly_patterns(console: Console, entries: list) -> None:
def _analyze_weekly_patterns(console: Console, entries: list[HistoryEntry]) -> None:
"""Analyze commands run at similar times weekly."""
weekly_patterns = defaultdict(list)
weekly_patterns: dict[tuple[int, int, int, int], list[str]] = defaultdict(list)
for entry in entries:
assert entry.timestamp is not None
key = (
entry.timestamp.isocalendar().year,
entry.timestamp.isocalendar().week,
@@ -219,11 +230,20 @@ def _analyze_weekly_patterns(console: Console, entries: list) -> None:
day_names = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
patterns_found = []
from typing import TypedDict
class WeeklyPattern(TypedDict):
week: int
day: str
hour: int
count: int
top: list[tuple[str, int]]
patterns_found: list[WeeklyPattern] = []
for key, cmds in weekly_patterns.items():
year, week, weekday, hour = key
if len(cmds) >= 2:
top = defaultdict(int)
top: dict[str, int] = defaultdict(int)
for cmd in cmds:
top[cmd] += 1
top_sorted = sorted(top.items(), key=lambda x: x[1], reverse=True)[:3]