Skip to content

Commit

Permalink
Assume that dataclasses have no dynamic attributes (#456)
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra authored Feb 3, 2022
1 parent 5c7d102 commit 2e96902
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- Assume that dataclasses have no dynamic attributes (#456)
- Treat Thrift enums as compatible with `int` (#455)
- Fix treatment of `TypeVar` with bounds or constraints
as callables (#454)
Expand Down
10 changes: 8 additions & 2 deletions pyanalyze/name_check_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,13 @@
from .patma import PatmaVisitor
from .shared_options import Paths, ImportPaths, EnforceNoUnused
from .reexport import ImplicitReexportTracker
from .safe import safe_getattr, is_hashable, all_of_type, safe_issubclass
from .safe import (
safe_getattr,
is_hashable,
all_of_type,
safe_issubclass,
is_dataclass_type,
)
from .stacked_scopes import (
EMPTY_ORIGIN,
AbstractConstraint,
Expand Down Expand Up @@ -4114,7 +4120,7 @@ def _has_only_known_attributes(self, typ: object) -> bool:
return True
ts_finder = self.checker.ts_finder
if (
ts_finder.has_stubs(typ)
(ts_finder.has_stubs(typ) or is_dataclass_type(typ))
and not ts_finder.has_attribute(typ, "__getattr__")
and not ts_finder.has_attribute(typ, "__getattribute__")
and not attributes.may_have_dynamic_attributes(typ)
Expand Down
9 changes: 9 additions & 0 deletions pyanalyze/safe.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,12 @@ def get_fully_qualified_name(obj: object) -> Optional[str]:
if hasattr(obj, "__module__") and hasattr(obj, "__qualname__"):
return f"{obj.__module__}.{obj.__qualname__}"
return None


def is_dataclass_type(cls: type) -> bool:
"""Like dataclasses.is_dataclass(), but works correctly for a
non-dataclass subclass of a dataclass."""
try:
return "__dataclass_fields__" in cls.__dict__
except Exception:
return False

0 comments on commit 2e96902

Please sign in to comment.