|
4 | 4 |
|
5 | 5 | from __future__ import annotations
|
6 | 6 |
|
| 7 | +import difflib |
7 | 8 | from typing import TYPE_CHECKING, TypeGuard, cast
|
8 | 9 |
|
9 | 10 | from astroid import nodes
|
@@ -74,6 +75,13 @@ class CodeStyleChecker(BaseChecker):
|
74 | 75 | "default_enabled": False,
|
75 | 76 | },
|
76 | 77 | ),
|
| 78 | + "R6106": ( |
| 79 | + "Consider %smath.%s instead of %s", |
| 80 | + "consider-math-not-float", |
| 81 | + "Using math.inf or math.nan permits to benefit from typing and it is up " |
| 82 | + "to 4 times faster than a float call (after the initial import of math). " |
| 83 | + "This check also catches typos in float calls as a side effect.", |
| 84 | + ), |
77 | 85 | }
|
78 | 86 | options = (
|
79 | 87 | (
|
@@ -101,14 +109,42 @@ def open(self) -> None:
|
101 | 109 | or self.linter.config.max_line_length
|
102 | 110 | )
|
103 | 111 |
|
104 |
| - @only_required_for_messages("prefer-typing-namedtuple") |
| 112 | + @only_required_for_messages("prefer-typing-namedtuple", "consider-math-not-float") |
105 | 113 | def visit_call(self, node: nodes.Call) -> None:
|
106 | 114 | if self._py36_plus:
|
107 | 115 | called = safe_infer(node.func)
|
108 |
| - if called and called.qname() == "collections.namedtuple": |
| 116 | + if not called: |
| 117 | + return |
| 118 | + if called.qname() == "collections.namedtuple": |
109 | 119 | self.add_message(
|
110 | 120 | "prefer-typing-namedtuple", node=node, confidence=INFERENCE
|
111 | 121 | )
|
| 122 | + elif called.qname() == "builtins.float": |
| 123 | + if ( |
| 124 | + node.args |
| 125 | + and isinstance(node.args[0], nodes.Const) |
| 126 | + and isinstance(node.args[0].value, str) |
| 127 | + and any( |
| 128 | + c.isalpha() and c.lower() != "e" for c in node.args[0].value |
| 129 | + ) |
| 130 | + ): |
| 131 | + value = node.args[0].value.lower() |
| 132 | + math_call: str |
| 133 | + if "nan" in value: |
| 134 | + math_call = "nan" |
| 135 | + elif "inf" in value: |
| 136 | + math_call = "inf" |
| 137 | + else: |
| 138 | + math_call = difflib.get_close_matches( |
| 139 | + value, ["inf", "nan"], n=1, cutoff=0 |
| 140 | + )[0] |
| 141 | + minus = "-" if math_call == "inf" and value.startswith("-") else "" |
| 142 | + self.add_message( |
| 143 | + "consider-math-not-float", |
| 144 | + node=node, |
| 145 | + args=(minus, math_call, node.as_string()), |
| 146 | + confidence=INFERENCE, |
| 147 | + ) |
112 | 148 |
|
113 | 149 | @only_required_for_messages("consider-using-namedtuple-or-dataclass")
|
114 | 150 | def visit_dict(self, node: nodes.Dict) -> None:
|
|
0 commit comments