-
-
Notifications
You must be signed in to change notification settings - Fork 644
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a mypy plugin to support @total_ordering. (#9525)
Without this, when using a comparison method synthesized by the `@total_ordering` class decorator, MyPy will incorrectly observe something like: ``` src/python/pants/option/option_value_container.py:108:12: error: Unsupported left operand type for >= ("Rank") [operator] if new_rank >= existing_rank: ^ Found 1 error in 1 file (checked 40 source files) ``` Here, just `__lt__` is explicitly defined in the "Rank" class and `@total_ordering` generates `__ge__` which MyPy is ignorant of. Also, in order to get the in-repo plugin working, fix the mypy task to upgrade its interpreter when `--include-requirements` is turned on and remove type checking tags from mypy example targets which are only ever used in integration tests where tags are not used as filters anyhow.
- Loading branch information
Showing
10 changed files
with
81 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
python_library( | ||
dependencies=[ | ||
'3rdparty/python:mypy', | ||
], | ||
tags = {'type_checked'}, | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
# See: https://mypy.readthedocs.io/en/latest/extending_mypy.html#high-level-overview | ||
|
||
from typing import Callable, Optional, Type | ||
|
||
from mypy.nodes import ARG_POS, Argument, TypeInfo, Var | ||
from mypy.plugin import ClassDefContext, Plugin | ||
from mypy.plugins.common import add_method | ||
|
||
|
||
class TotalOrderingPlugin(Plugin): | ||
@staticmethod | ||
def adjust_class_def(class_def_context: ClassDefContext) -> None: | ||
# This MyPy plugin inserts method type stubs for the "missing" ordering methods the | ||
# @total_ordering class decorator will fill in dynamically. | ||
|
||
api = class_def_context.api | ||
ordering_other_type = api.named_type("__builtins__.object") | ||
ordering_return_type = api.named_type("__builtins__.bool") | ||
args = [ | ||
Argument( | ||
variable=Var(name="other", type=ordering_other_type), | ||
type_annotation=ordering_other_type, | ||
initializer=None, | ||
kind=ARG_POS, | ||
) | ||
] | ||
|
||
type_info: TypeInfo = class_def_context.cls.info | ||
for ordering_method_name in "__lt__", "__le__", "__gt__", "__ge__": | ||
existing_method = type_info.get(ordering_method_name) | ||
if existing_method is None: | ||
add_method( | ||
ctx=class_def_context, | ||
name=ordering_method_name, | ||
args=args, | ||
return_type=ordering_return_type, | ||
) | ||
|
||
def get_class_decorator_hook( | ||
self, fullname: str | ||
) -> Optional[Callable[[ClassDefContext], None]]: | ||
return self.adjust_class_def if fullname == "functools.total_ordering" else None | ||
|
||
|
||
def plugin(_version: str) -> Type[Plugin]: | ||
return TotalOrderingPlugin |