glam/docs/sessions/2025-11-05-type-checking-fixes.md
2025-11-19 23:25:22 +01:00

5.1 KiB

Session Notes: Type Checking Fixes

Date: 2025-11-05
Status: Complete
Tests: 176/176 passing (89% coverage)
Mypy: All type errors resolved


Summary

Fixed all mypy type checking errors in parser modules by adding proper type annotations and configuring the Pydantic mypy plugin.


Changes Made

1. Added Pydantic Mypy Plugin (pyproject.toml)

Problem: Mypy doesn't understand that Pydantic v1 Optional fields with Field(None, ...) have default values, leading to false "missing required parameter" errors.

Solution: Added Pydantic mypy plugin configuration:

[tool.mypy]
plugins = ["pydantic.mypy"]

[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true

Impact: Eliminated 30+ false positive errors about "missing required parameters" in model instantiation.


2. Fixed Validator Type Annotations

dutch_orgs.py

Fixed missing type annotations on Pydantic validators:

# Before
@validator('type_organisatie')
def normalize_type(cls, v):
    ...

@validator('isil_code')
def normalize_isil(cls, v):
    ...

# After
@validator('type_organisatie')
def normalize_type(cls, v: Optional[str]) -> Optional[str]:
    ...

@validator('isil_code')
def normalize_isil(cls, v: Optional[str]) -> Optional[str]:
    ...

isil_registry.py

# Before
@validator('toegekend_op', pre=True)
def parse_date(cls, v):
    ...

@validator('isil_code')
def validate_isil(cls, v):
    ...

# After
@validator('toegekend_op', pre=True)
def parse_date(cls, v: Optional[str]) -> Optional[datetime]:
    ...

@validator('isil_code')
def validate_isil(cls, v: str) -> str:
    ...

3. Fixed __init__ Type Annotations

Both parsers had __init__ methods without return type annotations:

# Before
def __init__(self):
    pass

# After
def __init__(self) -> None:
    pass

Errors Fixed:

  • dutch_orgs.py:184: error: Function is missing a return type annotation
  • isil_registry.py:91: error: Function is missing a return type annotation

4. Fixed HttpUrl Type Issues

Problem

Mypy complained about assigning strings to HttpUrl typed fields:

error: Argument "identifier_url" to "Identifier" has incompatible type "str"; expected "HttpUrl | None"

Root Cause

Pydantic v1's HttpUrl is a validator type that accepts strings at runtime and validates/converts them. Mypy's static analysis doesn't understand this.

Solution

Added # type: ignore[arg-type] comments on the offending lines:

# dutch_orgs.py:286
identifier_url=f"https://isil.nl/{record.isil_code}"  # type: ignore[arg-type]

# isil_registry.py:255
identifier_url=f"https://isil.nl/{record.isil_code}"  # type: ignore[arg-type]

Why This Is Correct:

  • Pydantic v1 HttpUrl does accept strings (it's a validator, not a constructor)
  • The tests prove it works at runtime
  • The # type: ignore[arg-type] annotation is the recommended way to handle this known Pydantic + mypy limitation
  • Alternative would be to use AnyUrl or upgrade to Pydantic v2 (not in scope)

5. Added HttpUrl Import

Added HttpUrl to imports for proper type checking (even though we don't call it as a constructor):

# Both files
from pydantic import BaseModel, Field, HttpUrl, validator

Files Modified

  1. pyproject.toml - Added Pydantic mypy plugin configuration
  2. src/glam_extractor/parsers/dutch_orgs.py - Fixed 5 type errors
  3. src/glam_extractor/parsers/isil_registry.py - Fixed 5 type errors

Verification

Mypy Results

Before:

dutch_orgs.py: 31 errors
isil_registry.py: 30 errors
Total: 61 errors

After:

Success: no issues found in 2 source files

Test Results

All 176 tests passing:

  • tests/parsers/test_dutch_orgs.py: 18/18
  • tests/parsers/test_isil_registry.py: 10/10
  • tests/parsers/test_conversation.py: 25/25
  • All other tests: 123/123

Coverage

Maintained 89% overall coverage:

  • parsers/dutch_orgs.py: 98%
  • parsers/isil_registry.py: 83%

Key Learnings

Pydantic v1 + Mypy Integration

  1. Always configure the Pydantic plugin in pyproject.toml when using mypy with Pydantic
  2. HttpUrl is a validator type, not a constructor - pass strings directly
  3. Validators must have type annotations to satisfy strict mypy settings
  4. # type: ignore[arg-type] is appropriate for known Pydantic validator limitations

Type Annotation Best Practices

  1. Always annotate validator methods: (cls, v: Type) -> ReturnType
  2. Always annotate __init__ methods: -> None
  3. Use Optional[str] for nullable string validators
  4. Import all types used in annotations (even if only for typing)

Next Steps

All parser type errors fixed
Mypy configuration complete
Consider upgrading to Pydantic v2 in future (better mypy integration)
Add mypy checks to pre-commit hooks
Run mypy on entire codebase to find other issues


Session Duration: ~30 minutes
Next Session: Add tests for new TYPE_MAPPING entries or start conversation JSON parsing