Skip to content

Report invalid-abstract-method for @abstractmethod in non-abstract classes#3905

Open
nitishagar wants to merge 1 commit into
facebook:mainfrom
nitishagar:nitishagar/issue-3728-invalid-abstract-method
Open

Report invalid-abstract-method for @abstractmethod in non-abstract classes#3905
nitishagar wants to merge 1 commit into
facebook:mainfrom
nitishagar:nitishagar/issue-3728-invalid-abstract-method

Conversation

@nitishagar

Copy link
Copy Markdown
Contributor

Summary: Adds a new off-by-default lint rule invalid-abstract-method that
fires when a method decorated with @abstractmethod is defined in a class
that is not abstract (does not inherit from abc.ABC, use abc.ABCMeta,
have a transitive ABC base, or be a Protocol). Such a class is directly
instantiable at runtime while containing an unimplemented method — a likely
programming mistake.

The check runs inside solve_abstract_members (which already executes for
every class), guarded by !extends_abc() && !is_protocol() && !is_new_type().
It iterates the class's own declared fields (not MRO-inherited ones) and emits
one error per field whose ClassField::is_abstract() flag is set, pointing at
the method's definition range. The rule defaults to Severity::Ignore to
avoid breaking existing code without opt-in.

Fixes #3728

Test Plan:

  • cargo build -p pyrefly_config (clean)
  • cargo build -p pyrefly (clean)
  • cargo test -p pyrefly_config -- test_doc_headers test_doc_severities (2 passed)
  • cargo test -p pyrefly --lib abstract_methods (35 passed)
  • cargo test -p pyrefly --lib (5824 passed, 0 failed)
  • python3 test.py --no-test --no-conformance --no-jsonschema (clean, no new lint)

@github-actions

This comment has been minimized.

…asses

Summary: Adds a new off-by-default lint rule `invalid-abstract-method` that
fires when a method decorated with `@abstractmethod` is defined in a class
that is not abstract (does not inherit from `abc.ABC`, use `abc.ABCMeta`,
have a transitive ABC base, or be a Protocol). Such a class is directly
instantiable at runtime while containing an unimplemented method — a likely
programming mistake.

The check runs as a class-level diagnostic in `solve_class_checks`, alongside
the existing override/variance checks. It reuses the class field map those
checks already build and reports at each own method whose
`ClassField::is_abstract()` flag is set, guarded by
`!extends_abc() && !is_protocol() && !is_new_type()`. Running it here rather
than in the abstract-class check means it forces no field resolution for
modules that merely import the class, so laziness is preserved. The rule
defaults to `Severity::Ignore` to avoid breaking existing code without opt-in.

Fixes facebook#3728

Test Plan:
- cargo test -p pyrefly  (lib 5824 + laziness 18 + integration 301, 0 failed)
- cargo test -p pyrefly_config  (incl. test_doc_headers, test_doc_severities)
- cargo test -p pyrefly --lib abstract_methods  (35 passed)
- python3 test.py --no-test --no-conformance --no-jsonschema  (clean)
@nitishagar nitishagar force-pushed the nitishagar/issue-3728-invalid-abstract-method branch from b897614 to 6e3a633 Compare June 23, 2026 07:57
@github-actions github-actions Bot added size/l and removed size/l labels Jun 23, 2026
@github-actions

Copy link
Copy Markdown

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

no error when @abstractmethod is used on a non-ABC

1 participant