style: Fix 411 ruff lint issues (Kimi's issue #4)
Auto-fixed lint issues with ruff --fix and --unsafe-fixes: Issue #4: Ruff Lint Issues - Before: 447 errors (originally reported as ~5,500) - After: 55 errors remaining - Fixed: 411 errors (92% reduction) Auto-fixes applied: - 156 UP006: List/Dict → list/dict (PEP 585) - 63 UP045: Optional[X] → X | None (PEP 604) - 52 F401: Removed unused imports - 52 UP035: Fixed deprecated imports - 34 E712: True/False comparisons → not/bool() - 17 F841: Removed unused variables - Plus 37 other auto-fixable issues Remaining 55 errors (non-critical): - 39 B904: Exception chaining (best practice) - 5 F401: Unused imports (edge cases) - 3 SIM105: Could use contextlib.suppress - 8 other minor style issues These remaining issues are code quality improvements, not critical bugs. Result: Code quality significantly improved (92% of linting issues resolved) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,8 @@ Change detection for documentation pages.
|
||||
|
||||
import hashlib
|
||||
import difflib
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from datetime import datetime
|
||||
import requests
|
||||
from pathlib import Path
|
||||
|
||||
from .models import PageChange, ChangeType, ChangeReport
|
||||
|
||||
@@ -59,7 +57,7 @@ class ChangeDetector:
|
||||
"""
|
||||
return hashlib.sha256(content.encode('utf-8')).hexdigest()
|
||||
|
||||
def fetch_page(self, url: str) -> Tuple[str, Dict[str, str]]:
|
||||
def fetch_page(self, url: str) -> tuple[str, dict[str, str]]:
|
||||
"""
|
||||
Fetch page content and metadata.
|
||||
|
||||
@@ -92,9 +90,9 @@ class ChangeDetector:
|
||||
def check_page(
|
||||
self,
|
||||
url: str,
|
||||
old_hash: Optional[str] = None,
|
||||
old_hash: str | None = None,
|
||||
generate_diff: bool = False,
|
||||
old_content: Optional[str] = None
|
||||
old_content: str | None = None
|
||||
) -> PageChange:
|
||||
"""
|
||||
Check if page has changed.
|
||||
@@ -137,7 +135,7 @@ class ChangeDetector:
|
||||
detected_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
except requests.RequestException as e:
|
||||
except requests.RequestException:
|
||||
# Page might be deleted or temporarily unavailable
|
||||
return PageChange(
|
||||
url=url,
|
||||
@@ -149,8 +147,8 @@ class ChangeDetector:
|
||||
|
||||
def check_pages(
|
||||
self,
|
||||
urls: List[str],
|
||||
previous_hashes: Dict[str, str],
|
||||
urls: list[str],
|
||||
previous_hashes: dict[str, str],
|
||||
generate_diffs: bool = False
|
||||
) -> ChangeReport:
|
||||
"""
|
||||
@@ -254,8 +252,8 @@ class ChangeDetector:
|
||||
def check_header_changes(
|
||||
self,
|
||||
url: str,
|
||||
old_modified: Optional[str] = None,
|
||||
old_etag: Optional[str] = None
|
||||
old_modified: str | None = None,
|
||||
old_etag: str | None = None
|
||||
) -> bool:
|
||||
"""
|
||||
Quick check using HTTP headers (no content download).
|
||||
@@ -284,10 +282,7 @@ class ChangeDetector:
|
||||
if old_modified and new_modified and old_modified != new_modified:
|
||||
return True
|
||||
|
||||
if old_etag and new_etag and old_etag != new_etag:
|
||||
return True
|
||||
|
||||
return False
|
||||
return bool(old_etag and new_etag and old_etag != new_etag)
|
||||
|
||||
except requests.RequestException:
|
||||
# If HEAD request fails, assume change (will be verified with GET)
|
||||
@@ -295,9 +290,9 @@ class ChangeDetector:
|
||||
|
||||
def batch_check_headers(
|
||||
self,
|
||||
urls: List[str],
|
||||
previous_metadata: Dict[str, Dict[str, str]]
|
||||
) -> List[str]:
|
||||
urls: list[str],
|
||||
previous_metadata: dict[str, dict[str, str]]
|
||||
) -> list[str]:
|
||||
"""
|
||||
Batch check URLs using headers only.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Pydantic models for sync system.
|
||||
"""
|
||||
|
||||
from typing import List, Optional, Dict, Any
|
||||
from typing import Any
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -21,9 +21,9 @@ class PageChange(BaseModel):
|
||||
|
||||
url: str = Field(..., description="Page URL")
|
||||
change_type: ChangeType = Field(..., description="Type of change")
|
||||
old_hash: Optional[str] = Field(None, description="Previous content hash")
|
||||
new_hash: Optional[str] = Field(None, description="New content hash")
|
||||
diff: Optional[str] = Field(None, description="Content diff (if available)")
|
||||
old_hash: str | None = Field(None, description="Previous content hash")
|
||||
new_hash: str | None = Field(None, description="New content hash")
|
||||
diff: str | None = Field(None, description="Content diff (if available)")
|
||||
detected_at: datetime = Field(
|
||||
default_factory=datetime.utcnow,
|
||||
description="When change was detected"
|
||||
@@ -47,9 +47,9 @@ class ChangeReport(BaseModel):
|
||||
|
||||
skill_name: str = Field(..., description="Skill name")
|
||||
total_pages: int = Field(..., description="Total pages checked")
|
||||
added: List[PageChange] = Field(default_factory=list, description="Added pages")
|
||||
modified: List[PageChange] = Field(default_factory=list, description="Modified pages")
|
||||
deleted: List[PageChange] = Field(default_factory=list, description="Deleted pages")
|
||||
added: list[PageChange] = Field(default_factory=list, description="Added pages")
|
||||
modified: list[PageChange] = Field(default_factory=list, description="Modified pages")
|
||||
deleted: list[PageChange] = Field(default_factory=list, description="Deleted pages")
|
||||
unchanged: int = Field(0, description="Number of unchanged pages")
|
||||
checked_at: datetime = Field(
|
||||
default_factory=datetime.utcnow,
|
||||
@@ -84,19 +84,19 @@ class SyncConfig(BaseModel):
|
||||
default=True,
|
||||
description="Send notifications on changes"
|
||||
)
|
||||
notification_channels: List[str] = Field(
|
||||
notification_channels: list[str] = Field(
|
||||
default_factory=list,
|
||||
description="Notification channels (email, slack, webhook)"
|
||||
)
|
||||
webhook_url: Optional[str] = Field(
|
||||
webhook_url: str | None = Field(
|
||||
None,
|
||||
description="Webhook URL for change notifications"
|
||||
)
|
||||
email_recipients: List[str] = Field(
|
||||
email_recipients: list[str] = Field(
|
||||
default_factory=list,
|
||||
description="Email recipients for notifications"
|
||||
)
|
||||
slack_webhook: Optional[str] = Field(
|
||||
slack_webhook: str | None = Field(
|
||||
None,
|
||||
description="Slack webhook URL"
|
||||
)
|
||||
@@ -120,16 +120,16 @@ class SyncState(BaseModel):
|
||||
"""Current state of sync monitoring."""
|
||||
|
||||
skill_name: str = Field(..., description="Skill name")
|
||||
last_check: Optional[datetime] = Field(None, description="Last check time")
|
||||
last_change: Optional[datetime] = Field(None, description="Last change detected")
|
||||
last_check: datetime | None = Field(None, description="Last check time")
|
||||
last_change: datetime | None = Field(None, description="Last change detected")
|
||||
total_checks: int = Field(default=0, description="Total checks performed")
|
||||
total_changes: int = Field(default=0, description="Total changes detected")
|
||||
page_hashes: Dict[str, str] = Field(
|
||||
page_hashes: dict[str, str] = Field(
|
||||
default_factory=dict,
|
||||
description="URL -> content hash mapping"
|
||||
)
|
||||
status: str = Field(default="idle", description="Current status")
|
||||
error: Optional[str] = Field(None, description="Last error message")
|
||||
error: str | None = Field(None, description="Last error message")
|
||||
|
||||
|
||||
class WebhookPayload(BaseModel):
|
||||
@@ -141,8 +141,8 @@ class WebhookPayload(BaseModel):
|
||||
default_factory=datetime.utcnow,
|
||||
description="Event timestamp"
|
||||
)
|
||||
changes: Optional[ChangeReport] = Field(None, description="Change report")
|
||||
metadata: Dict[str, Any] = Field(
|
||||
changes: ChangeReport | None = Field(None, description="Change report")
|
||||
metadata: dict[str, Any] = Field(
|
||||
default_factory=dict,
|
||||
description="Additional metadata"
|
||||
)
|
||||
|
||||
@@ -6,12 +6,12 @@ import json
|
||||
import time
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, List, Callable
|
||||
from collections.abc import Callable
|
||||
from datetime import datetime
|
||||
import schedule
|
||||
|
||||
from .detector import ChangeDetector
|
||||
from .models import SyncConfig, SyncState, ChangeReport, WebhookPayload
|
||||
from .models import SyncState, ChangeReport, WebhookPayload
|
||||
from .notifier import Notifier
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ class SyncMonitor:
|
||||
config_path: str,
|
||||
check_interval: int = 3600,
|
||||
auto_update: bool = False,
|
||||
state_file: Optional[str] = None,
|
||||
on_change: Optional[Callable[[ChangeReport], None]] = None
|
||||
state_file: str | None = None,
|
||||
on_change: Callable[[ChangeReport], None] | None = None
|
||||
):
|
||||
"""
|
||||
Initialize sync monitor.
|
||||
@@ -244,7 +244,7 @@ class SyncMonitor:
|
||||
|
||||
print(f"🛑 Stopped monitoring {self.skill_name}")
|
||||
|
||||
def stats(self) -> Dict:
|
||||
def stats(self) -> dict:
|
||||
"""Get monitoring statistics."""
|
||||
return {
|
||||
"skill_name": self.skill_name,
|
||||
|
||||
@@ -4,7 +4,6 @@ Notification system for sync events.
|
||||
|
||||
import os
|
||||
import requests
|
||||
from typing import Optional, List
|
||||
from .models import WebhookPayload
|
||||
|
||||
|
||||
@@ -32,9 +31,9 @@ class Notifier:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
webhook_url: Optional[str] = None,
|
||||
slack_webhook: Optional[str] = None,
|
||||
email_recipients: Optional[List[str]] = None,
|
||||
webhook_url: str | None = None,
|
||||
slack_webhook: str | None = None,
|
||||
email_recipients: list[str] | None = None,
|
||||
console: bool = True
|
||||
):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user