Overview
Running uv run pyright . reveals 415 type errors across the codebase. These should be fixed to improve type safety, IDE support, and prevent runtime errors. After fixing, pyright should be added as a pre-commit hook to prevent regressions.
Error Summary
415 errors, 0 warnings, 0 informations
Error Categories
1. None/Optional Parameter Type Errors (~80 errors)
Pattern: Expression of type "None" cannot be assigned to parameter
Files affected:
src/agents/base/interface.py (lines 15, 43)
src/agents/llm/factory.py (lines 46, 97, 127)
src/agents/llm/hybrid.py (lines 43, 202)
src/agents/rule_based/sentiment.py (lines 17, 35)
src/agents/rule_based/synthesis.py (lines 15, 32)
src/analysis/fundamental.py (lines 32-34, 152-155)
Example:
# src/agents/base/interface.py:15
def __init__(self, tools: list = None): # ❌ None not assignable to list
# Should be:
def __init__(self, tools: Optional[list] = None): # ✅
self.tools = tools or []
Fix: Add proper Optional[] type hints and handle None cases
2. Missing Pydantic Model Parameters (~120 errors)
Pattern: No parameter named "rsi", Arguments missing for parameters
Files affected:
src/analysis/metadata_extractor.py (lines 42-50)
src/analysis/normalizer.py (lines 499-507, 1201, 1231)
tests/unit/website/test_generator_comprehensive.py (lines 36-50)
Example:
# Attempting to create TechnicalMetrics without required fields
TechnicalMetrics(
rsi=70.5, # ❌ Not a parameter
macd=0.5, # ❌ Not a parameter
sma_20=150.0 # ❌ Not a parameter
)
# TechnicalMetrics likely defined as:
class TechnicalMetrics(BaseModel):
# Missing field definitions
pass
Root cause: Pydantic models missing field definitions
Fix: Add all required fields to Pydantic models or use model_construct() for dynamic creation
3. Type Narrowing Issues (~100 errors)
Pattern: Cannot access attribute "X" for class "dict[str, Any]"
Files affected:
src/analysis/normalizer.py (lines 111-138, 432-665)
src/agents/llm/hybrid.py (line 87)
Example:
# normalizer.py:111
synth_result: dict[str, Any] = get_synthesis()
risk_level = synth_result.risk_level # ❌ .risk_level not defined on dict
# Fix: Type narrowing or Pydantic validation
synth_result: SignalSynthesisOutput = get_synthesis()
risk_level = synth_result.risk_level # ✅
Fix: Replace dict[str, Any] with proper Pydantic models or add type narrowing
4. pandas-ta Type Issues (~50 errors)
Pattern: Argument of type "Series | DataFrame" cannot be assigned to parameter "close" of type "Series"
Files affected:
src/analysis/technical_indicators.py (lines 193-280)
Example:
# technical_indicators.py:193
close_series = df['close'] # Type: Series | DataFrame (union type)
rsi_value = ta.rsi(close_series, length=14) # ❌ ta.rsi expects Series only
# Fix: Type assertion
close_series = df['close']
assert isinstance(close_series, pd.Series)
rsi_value = ta.rsi(close_series, length=14) # ✅
Fix: Add type assertions after DataFrame column access
5. Possibly Unbound Variables (~10 errors)
Pattern: "ta" is possibly unbound
Files affected:
src/analysis/technical_indicators.py (lines 62-280)
Example:
try:
import pandas_ta as ta
except ImportError:
logger.error("pandas_ta not available")
# ta not defined here
result = ta.rsi(...) # ❌ ta possibly unbound
Fix: Define fallback or raise ImportError immediately
6. String vs Enum Type Errors (~20 errors)
Pattern: "str" is not assignable to "Recommendation"
Files affected:
src/analysis/signal_creator.py (line 109)
Example:
# signal_creator.py:109
recommendation: str = "buy"
signal = InvestmentSignal(recommendation=recommendation) # ❌
# Fix: Use enum
from src.analysis.models import Recommendation
recommendation = Recommendation.BUY # ✅
Fix: Use proper enum types instead of strings
7. Missing Private Method Definitions (~15 errors)
Pattern: Cannot access attribute "_extract_from_technical_pydantic"
Files affected:
src/analysis/normalizer.py (lines 432, 434, 438, 531, 533, etc.)
Example:
# normalizer.py:432
result = AnalysisResultNormalizer._extract_from_technical_pydantic(data)
# ❌ Method doesn't exist or isn't marked as @staticmethod/@classmethod
Fix: Define missing methods or fix method visibility
8. Test Fixture Issues (~20 errors)
Pattern: Cannot assign to attribute, None is not assignable
Files affected:
tests/unit/website/test_generator_comprehensive.py (lines 730, 743)
Example:
signal.risk = None # ❌ risk expects RiskAssessment, not None
signal.scores = None # ❌ scores expects ComponentScores, not None
Fix: Use proper mock objects or make fields Optional
Implementation Plan
Phase 1: Low-Hanging Fruit (Est: 2-4 hours)
Phase 2: Pydantic Model Fixes (Est: 4-6 hours)
Phase 3: Type Narrowing (Est: 6-8 hours)
Phase 4: Enum and Edge Cases (Est: 2-3 hours)
Phase 5: Validation (Est: 1 hour)
Add Pyright to Pre-Commit
After all errors are fixed, add to .pre-commit-config.yaml:
- repo: local
hooks:
# ... existing hooks ...
- id: pyright
name: pyright
entry: uv run pyright
language: system
types: [python]
pass_filenames: false
stages: [commit]
Note: Only add after ALL errors are fixed (0 errors), otherwise pre-commit will block all commits.
Benefits
✅ Better IDE support - VSCode/PyCharm will provide accurate autocomplete
✅ Catch bugs early - Type errors caught before runtime
✅ Improved refactoring - Safer code changes with type checking
✅ Better documentation - Types serve as inline documentation
✅ Prevent regressions - Pre-commit hook ensures type safety maintained
Success Criteria
Related Issues
Priority
MEDIUM-HIGH - Improves code quality and developer experience, but doesn't block functionality
Overview
Running
uv run pyright .reveals 415 type errors across the codebase. These should be fixed to improve type safety, IDE support, and prevent runtime errors. After fixing, pyright should be added as a pre-commit hook to prevent regressions.Error Summary
Error Categories
1. None/Optional Parameter Type Errors (~80 errors)
Pattern:
Expression of type "None" cannot be assigned to parameterFiles affected:
src/agents/base/interface.py(lines 15, 43)src/agents/llm/factory.py(lines 46, 97, 127)src/agents/llm/hybrid.py(lines 43, 202)src/agents/rule_based/sentiment.py(lines 17, 35)src/agents/rule_based/synthesis.py(lines 15, 32)src/analysis/fundamental.py(lines 32-34, 152-155)Example:
Fix: Add proper
Optional[]type hints and handle None cases2. Missing Pydantic Model Parameters (~120 errors)
Pattern:
No parameter named "rsi",Arguments missing for parametersFiles affected:
src/analysis/metadata_extractor.py(lines 42-50)src/analysis/normalizer.py(lines 499-507, 1201, 1231)tests/unit/website/test_generator_comprehensive.py(lines 36-50)Example:
Root cause: Pydantic models missing field definitions
Fix: Add all required fields to Pydantic models or use
model_construct()for dynamic creation3. Type Narrowing Issues (~100 errors)
Pattern:
Cannot access attribute "X" for class "dict[str, Any]"Files affected:
src/analysis/normalizer.py(lines 111-138, 432-665)src/agents/llm/hybrid.py(line 87)Example:
Fix: Replace
dict[str, Any]with proper Pydantic models or add type narrowing4. pandas-ta Type Issues (~50 errors)
Pattern:
Argument of type "Series | DataFrame" cannot be assigned to parameter "close" of type "Series"Files affected:
src/analysis/technical_indicators.py(lines 193-280)Example:
Fix: Add type assertions after DataFrame column access
5. Possibly Unbound Variables (~10 errors)
Pattern:
"ta" is possibly unboundFiles affected:
src/analysis/technical_indicators.py(lines 62-280)Example:
Fix: Define fallback or raise ImportError immediately
6. String vs Enum Type Errors (~20 errors)
Pattern:
"str" is not assignable to "Recommendation"Files affected:
src/analysis/signal_creator.py(line 109)Example:
Fix: Use proper enum types instead of strings
7. Missing Private Method Definitions (~15 errors)
Pattern:
Cannot access attribute "_extract_from_technical_pydantic"Files affected:
src/analysis/normalizer.py(lines 432, 434, 438, 531, 533, etc.)Example:
Fix: Define missing methods or fix method visibility
8. Test Fixture Issues (~20 errors)
Pattern:
Cannot assign to attribute,None is not assignableFiles affected:
tests/unit/website/test_generator_comprehensive.py(lines 730, 743)Example:
Fix: Use proper mock objects or make fields Optional
Implementation Plan
Phase 1: Low-Hanging Fruit (Est: 2-4 hours)
Phase 2: Pydantic Model Fixes (Est: 4-6 hours)
Phase 3: Type Narrowing (Est: 6-8 hours)
Phase 4: Enum and Edge Cases (Est: 2-3 hours)
Phase 5: Validation (Est: 1 hour)
uv run pyright .- should show 0 errorsAdd Pyright to Pre-Commit
After all errors are fixed, add to
.pre-commit-config.yaml:Note: Only add after ALL errors are fixed (0 errors), otherwise pre-commit will block all commits.
Benefits
✅ Better IDE support - VSCode/PyCharm will provide accurate autocomplete
✅ Catch bugs early - Type errors caught before runtime
✅ Improved refactoring - Safer code changes with type checking
✅ Better documentation - Types serve as inline documentation
✅ Prevent regressions - Pre-commit hook ensures type safety maintained
Success Criteria
uv run pyright .shows 0 errors.pre-commit-config.yamlRelated Issues
Priority
MEDIUM-HIGH - Improves code quality and developer experience, but doesn't block functionality