fix: resolve CI type checking issues
- 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:
@@ -8,7 +8,7 @@ import click
|
|||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
|
|
||||||
from shellhist.core import HistoryLoader
|
from shellhist.core import HistoryLoader, HistoryEntry
|
||||||
|
|
||||||
|
|
||||||
@click.command("analyze-time")
|
@click.command("analyze-time")
|
||||||
@@ -84,7 +84,7 @@ def analyze_time_command(
|
|||||||
cutoff = _parse_time_range(time_range)
|
cutoff = _parse_time_range(time_range)
|
||||||
recent_entries = [
|
recent_entries = [
|
||||||
e for e in entries_with_time
|
e for e in entries_with_time
|
||||||
if e.timestamp >= cutoff
|
if e.timestamp is not None and e.timestamp >= cutoff
|
||||||
]
|
]
|
||||||
|
|
||||||
if daily:
|
if daily:
|
||||||
@@ -119,11 +119,12 @@ def _parse_time_range(time_range: str) -> datetime:
|
|||||||
return now - timedelta(days=7)
|
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."""
|
"""Analyze command distribution by hour of day."""
|
||||||
hourly = defaultdict(list)
|
hourly: dict[int, list[str]] = defaultdict(list)
|
||||||
|
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
|
assert entry.timestamp is not None
|
||||||
hour = entry.timestamp.hour
|
hour = entry.timestamp.hour
|
||||||
hourly[hour].append(entry.command)
|
hourly[hour].append(entry.command)
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ def _analyze_hourly_distribution(console: Console, entries: list) -> None:
|
|||||||
for hour in range(24):
|
for hour in range(24):
|
||||||
cmds = hourly.get(hour, [])
|
cmds = hourly.get(hour, [])
|
||||||
if cmds:
|
if cmds:
|
||||||
top = defaultdict(int)
|
top: dict[str, int] = defaultdict(int)
|
||||||
for cmd in cmds:
|
for cmd in cmds:
|
||||||
top[cmd] += 1
|
top[cmd] += 1
|
||||||
top_sorted = sorted(top.items(), key=lambda x: x[1], reverse=True)[:2]
|
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)
|
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."""
|
"""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:
|
for entry in entries:
|
||||||
|
assert entry.timestamp is not None
|
||||||
hour = entry.timestamp.hour
|
hour = entry.timestamp.hour
|
||||||
key = (entry.timestamp.weekday(), hour)
|
key = (entry.timestamp.weekday(), hour)
|
||||||
daily_patterns[key].append(entry.command)
|
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"]
|
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():
|
for (weekday, hour), cmds in daily_patterns.items():
|
||||||
if len(cmds) >= 2:
|
if len(cmds) >= 2:
|
||||||
top = defaultdict(int)
|
top: dict[str, int] = defaultdict(int)
|
||||||
for cmd in cmds:
|
for cmd in cmds:
|
||||||
top[cmd] += 1
|
top[cmd] += 1
|
||||||
top_sorted = sorted(top.items(), key=lambda x: x[1], reverse=True)[:3]
|
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)
|
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."""
|
"""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:
|
for entry in entries:
|
||||||
|
assert entry.timestamp is not None
|
||||||
key = (
|
key = (
|
||||||
entry.timestamp.isocalendar().year,
|
entry.timestamp.isocalendar().year,
|
||||||
entry.timestamp.isocalendar().week,
|
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"]
|
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():
|
for key, cmds in weekly_patterns.items():
|
||||||
year, week, weekday, hour = key
|
year, week, weekday, hour = key
|
||||||
if len(cmds) >= 2:
|
if len(cmds) >= 2:
|
||||||
top = defaultdict(int)
|
top: dict[str, int] = defaultdict(int)
|
||||||
for cmd in cmds:
|
for cmd in cmds:
|
||||||
top[cmd] += 1
|
top[cmd] += 1
|
||||||
top_sorted = sorted(top.items(), key=lambda x: x[1], reverse=True)[:3]
|
top_sorted = sorted(top.items(), key=lambda x: x[1], reverse=True)[:3]
|
||||||
|
|||||||
Reference in New Issue
Block a user