Open
Description
Describe the Bug
Pyrefly Bug Report: False Positive "missing-attribute" on Union Types
Summary
Pyrefly 0.20.2 incorrectly reports "missing-attribute" errors when accessing methods on dictionary values within union types, even when proper type narrowing or initialization guarantees the correct type.
Environment
- Pyrefly version: 0.20.2
- Python version: 3.12
- OS: Linux
Minimal Reproducible Example
from typing import Dict, Any, List, Union
def process_sla_result() -> Dict[str, Any]:
# Initialize with explicit structure
sla_result = {
"sla_id": "sla-001",
"sla_name": "Response Time SLA",
"compliant": True,
"violations": [], # Clearly a list
"metrics_checked": {}
}
# Pyrefly reports these as errors:
# ERROR Object of class `bool` has no attribute `append` [missing-attribute]
# ERROR Object of class `dict` has no attribute `append` [missing-attribute]
sla_result["violations"].append({
"type": "response_time",
"severity": "high"
})
return sla_result
# Another example with TypedDict
from typing import TypedDict, List
class SLAResult(TypedDict):
violations: List[Dict[str, Any]]
compliant: bool
def process_typed() -> SLAResult:
result: SLAResult = {
"violations": [],
"compliant": True
}
# Still reports error even with TypedDict
result["violations"].append({"error": "timeout"})
return result
Expected Behavior
- Pyrefly should recognize that
sla_result["violations"]
is initialized as a list - When using TypedDict, the type of
violations
is explicitlyList[Dict[str, Any]]
- No "missing-attribute" error should be reported for the
append
method
Actual Behavior
Pyrefly reports multiple errors:
ERROR Object of class `bool` has no attribute `append` [missing-attribute]
ERROR Object of class `dict` has no attribute `append` [missing-attribute]
ERROR Object of class `int` has no attribute `append` [missing-attribute]
ERROR Object of class `str` has no attribute `append` [missing-attribute]
Root Cause Analysis
- When accessing
dict[key]
, pyrefly considers all possible types in the unionDict[str, Any]
- The
Any
type expands to a union includingbool | dict | int | str | list | ...
- Pyrefly checks each type in the union and reports errors for types that don't have
append
- It doesn't recognize that in this specific context, the value is guaranteed to be a list
Impact
- 378+ false positive "missing-attribute" errors in our codebase
- Makes pyrefly output noisy and less useful
- Developers may miss real type errors among the false positives
Suggested Fix
- Improve flow-sensitive type analysis to track dictionary value types after initialization
- When a dictionary key is initialized with a specific type, narrow the type for that key
- Consider TypedDict annotations when analyzing dictionary access
- Reduce false positives by considering whether ANY type in the union has the attribute
Workarounds
-
Use explicit type annotations:
violations: List[Dict[str, Any]] = sla_result["violations"] violations.append({"error": "timeout"})
-
Use isinstance checks:
if isinstance(sla_result["violations"], list): sla_result["violations"].append({"error": "timeout"})
-
Use TypedDict throughout:
result: SLAResult = {"violations": [], "compliant": True} violations = result["violations"] # Type is known violations.append({"error": "timeout"})
Additional Context
This pattern is extremely common in Python code dealing with JSON-like data structures, configuration management, and API responses. The false positives significantly impact pyrefly's usability for real-world Python projects.
Sandbox Link
No response
(Only applicable for extension issues) IDE Information
No response