Skip to content

Warn when abstract or protocol type is assigned to a callable #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

arvi18
Copy link

@arvi18 arvi18 commented Apr 25, 2025

Now Callable[[], AbstractOrProtocol] has the same semantics as Type[AbstractOrProtocol].
I don't think we need to test for @overload here, because you cannot have inline @overload annotation.

Closes python#13171

Summary by CodeRabbit

  • Refactor

    • Improved internal handling of assignments involving abstract classes and protocols to ensure more consistent type checking.
  • Tests

    • Added new tests verifying assignments to variables typed as callables returning abstract or protocol instances.
    • Ensured only concrete classes can be assigned to callable-typed variables returning abstract or protocol types.

@arvi18
Copy link
Author

arvi18 commented Apr 25, 2025

Diff from mypy_primer, showing the effect of this PR on open source code:

ignite (https://github.com/pytorch/ignite)
+ ignite/contrib/handlers/param_scheduler.py:44: error: Can only assign concrete classes to a variable of type "Type[ParamScheduler]"  [misc]
+ ignite/contrib/handlers/param_scheduler.py:46: error: Can only assign concrete classes to a variable of type "Type[CyclicalScheduler]"  [misc]

@arvi18
Copy link
Author

arvi18 commented Apr 25, 2025

This is interesting 🤔
What it does is:

from ignite.handlers.param_scheduler import (
    ParamScheduler,
)

ParamScheduler = ParamScheduler

Where ParamScheduler is an abstract class.

I think that this should be fine. It does not look like an issue to me.
But, I cannot formulate the rule here.

I am also ok if others are fine with ignoring it.

@arvi18
Copy link
Author

arvi18 commented Apr 25, 2025

Diff from mypy_primer, showing the effect of this PR on open source code:

ignite (https://github.com/pytorch/ignite)
+ ignite/contrib/handlers/param_scheduler.py:44: error: Can only assign concrete classes to a variable of type "Type[ParamScheduler]"  [misc]
+ ignite/contrib/handlers/param_scheduler.py:46: error: Can only assign concrete classes to a variable of type "Type[CyclicalScheduler]"  [misc]

@arvi18
Copy link
Author

arvi18 commented Apr 25, 2025

I think that this should be fine. It does not look like an issue to me. But, I cannot formulate the rule here

Yeah, I think that this should be allowed. Maybe check if the lvalue and rvalue refer to the same node, and skip the concreteness check in this case? The assignment will be a no-op.

Copy link

coderabbitai bot commented Apr 25, 2025

Walkthrough

This change refactors the logic in the mypy type checker's assignment validation to extract the check for assignments involving abstract classes and protocols into a new method, check_concrete_only_assign. The method centralizes logic to ensure that only concrete classes can be assigned where required, particularly for assignments involving Type[A] and Callable types returning abstract or protocol instances. Additionally, new test cases are added to verify that assignments involving abstract classes and protocols with Callable types behave as expected, ensuring errors are raised when necessary and valid assignments are accepted.

Changes

File(s) Change Summary
mypy/checker.py Refactored assignment checking logic: extracted special-case logic for abstract/protocol assignment checks into a new method check_concrete_only_assign within the TypeChecker class. The main assignment check now calls this method and returns early if assignment is not allowed.
test-data/unit/check-abstract.test Added new test case testInstantiationAbstractsWithCallables to verify assignment and instantiation rules for abstract classes using Callable types.
test-data/unit/check-protocols.test Added new test case testInstantiationProtocolWithCallables to verify assignment and instantiation rules for protocol classes using Callable types.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant TypeChecker as TypeChecker
    participant check_concrete_only_assign as check_concrete_only_assign

    User->>TypeChecker: check_assignment(lvalue_type, lvalue, rvalue_type, rvalue)
    TypeChecker->>check_concrete_only_assign: check_concrete_only_assign(lvalue_type, lvalue, rvalue_type, rvalue)
    check_concrete_only_assign-->>TypeChecker: (True/False)
    alt Assignment not allowed
        TypeChecker-->>User: Return early (error emitted)
    else Assignment allowed
        TypeChecker->>User: Continue with assignment check
    end
Loading

Poem

In burrows deep where type checks dwell,
A rabbit hops with code to tell:
Abstracts and protocols, now checked with care,
In callables’ paws, only concretes dare.
Refactored logic, tests anew—
The warren’s type rules strong and true!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between 380cb8d and 6a06e36.

📒 Files selected for processing (3)
  • mypy/checker.py (2 hunks)
  • test-data/unit/check-abstract.test (1 hunks)
  • test-data/unit/check-protocols.test (1 hunks)
🔇 Additional comments (4)
mypy/checker.py (2)

2447-2486: Well-implemented abstract/protocol type assignment checker.

This new method implements the intended functionality to warn when abstract or protocol classes are assigned to Callable return types, giving them the same semantics as Type[AbstractOrProtocol]. The code correctly handles self-assignments like A = A and properly checks for both TypeType and CallableType cases.

The implementation also has a nice safeguard to skip checks for self-assignments of abstract classes, which addresses the edge case identified during PR discussions about the PyTorch Ignite repository issues.


2429-2430: Good integration of the new concrete type validator.

This call correctly integrates the extracted validation logic into the existing type checking flow, allowing the assignment checker to return early if an abstract or protocol type is being incorrectly assigned.

test-data/unit/check-protocols.test (1)

1622-1651: Well-structured test case for verifying protocol assignment to callables.

This test case properly verifies that concrete classes can be assigned to Callable[[], P] while protocols themselves cannot, mirroring the behavior of Type[P]. The test covers both direct class assignments and type aliases, as well as self-assignments.

The validation checks three key scenarios:

  1. Using protocols directly with callable types
  2. Using type aliases with callable types
  3. Allowing self-assignments which are always valid
test-data/unit/check-abstract.test (1)

253-284: Comprehensive test for abstract class assignment to callables.

This test case correctly validates that only concrete classes can be assigned to Callable[[], A] variables, mirroring the behavior of Type[A]. The test properly covers direct class assignments, type aliases, and self-assignments.

The test successfully verifies:

  1. Abstract classes A and B cannot be assigned to variables of type Callable[[], A]
  2. Concrete class C can be assigned to such variables
  3. The same rules apply when using type aliases
  4. Self-assignment is always allowed (e.g., A = A)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@arvi18
Copy link
Author

arvi18 commented Apr 25, 2025

Done!

@arvi18
Copy link
Author

arvi18 commented Apr 25, 2025

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @arvi18, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Summary of Changes

This pull request addresses issue python#13171 by adding a warning when an abstract or protocol type is assigned to a callable. The changes modify mypy/checker.py to include a check that emits an error when this type of assignment occurs. Additionally, new test cases are added to test-data/unit/check-abstract.test and test-data/unit/check-protocols.test to verify the new warning.

Highlights

  • New Warning: Introduces a warning when assigning an abstract or protocol type to a callable, mirroring the behavior of Type[AbstractOrProtocol].
  • Code Refactoring: Refactors the check_assignment function in mypy/checker.py to use a new helper function check_concrete_only_assign for checking concrete assignments.
  • New Test Cases: Adds new test cases to test-data/unit/check-abstract.test and test-data/unit/check-protocols.test to cover the new warning scenario.

Changelog

  • mypy/checker.py
    • Refactors check_assignment to extract the logic for checking concrete-only assignments into a new function check_concrete_only_assign.
    • Adds a check within check_concrete_only_assign to warn when an abstract or protocol type is assigned to a callable.
    • Adds a condition to allow reassigning an abstract class to itself (e.g., A = A).
  • test-data/unit/check-abstract.test
    • Adds a new test case testInstantiationAbstractsWithCallables to verify the warning for abstract types assigned to callables.
  • test-data/unit/check-protocols.test
    • Adds a new test case testInstantiationProtocolWithCallables to verify the warning for protocol types assigned to callables.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


A callable's plight,
Abstract types cause a fright,
Concrete's the key,
For functions to be,
Error's gone, code shines bright.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces a new check in mypy to warn when an abstract or protocol type is assigned to a callable, aligning the semantics with Type[AbstractOrProtocol]. The changes include modifications to mypy/checker.py and additions to test-data/unit/check-abstract.test and test-data/unit/check-protocols.test to incorporate the new functionality and test cases. Overall, the changes seem well-structured and address the intended issue.

Summary of Findings

  • Code Duplication: The logic for checking concrete-only assignments is duplicated within the check_assignment method. Extracting this logic into a separate, reusable function would improve maintainability and reduce redundancy.
  • Clarity of Conditionals: The conditional logic in check_concrete_only_assign could be simplified for better readability. Consider using intermediate variables with descriptive names to clarify the conditions being checked.
  • Missing Error Code: The error message concrete_only_assign in check_concrete_only_assign is missing an associated error code. Adding an error code would improve the ability to filter and manage these errors.

Merge Readiness

The pull request introduces a valuable new check. However, addressing the identified issues related to code duplication, conditional clarity, and the missing error code would further enhance the quality and maintainability of the code. I recommend addressing these points before merging. I am unable to directly approve this pull request, and recommend that others review and approve this code before merging.

@visz11
Copy link
Collaborator

visz11 commented Apr 28, 2025

@coderabbitai full review

Copy link

coderabbitai bot commented Apr 28, 2025

✅ Actions performed

Full review triggered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants