Skip to content

Commit b1ee795

Browse files
Merge pull request #20086 from joefarebrother/python-qual-raise-not-implemented
Python: Modernise raise-not-implemented query
2 parents 621b483 + a8cc144 commit b1ee795

File tree

3 files changed

+24
-14
lines changed

3 files changed

+24
-14
lines changed

python/ql/src/Exceptions/NotImplementedIsNotAnException.qhelp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,25 @@
44
<qhelp>
55
<overview>
66

7-
<p><code>NotImplemented</code> is not an Exception, but is often mistakenly used in place of <code>NotImplementedError</code>.
8-
Executing <code>raise NotImplemented</code> or <code>raise NotImplemented()</code> will raise a <code>TypeError</code>.
9-
When <code>raise NotImplemented</code> is used to mark code that is genuinely never called, this mistake is benign.
10-
11-
However, should it be called, then a <code>TypeError</code> will be raised rather than the expected <code>NotImplemented</code>,
12-
which might make debugging the issue difficult.
7+
<p>
8+
The constant <code>NotImplemented</code> is not an <code>Exception</code>, but is often confused for <code>NotImplementedError</code>.
9+
If it is used as an exception, such as in <code>raise NotImplemented</code> or <code>raise NotImplemented("message")</code>,
10+
a <code>TypeError</code> will be raised rather than the expected <code>NotImplemented</code>. This may make debugging more difficult.
1311
</p>
1412

15-
<p>The correct use of <code>NotImplemented</code> is to implement binary operators.
13+
<p><code>NotImplemented</code> should only be used as a special return value for implementing special methods such as <code>__lt__</code>.
1614
Code that is not intended to be called should raise <code>NotImplementedError</code>.</p>
1715

1816
</overview>
1917
<recommendation>
20-
<p>Replace uses of <code>NotImplemented</code> with <code>NotImplementedError</code>.</p>
18+
<p>If a <code>NotImplementedError</code> is intended to be raised, replace the use of <code>NotImplemented</code>
19+
with that. If <code>NotImplemented</code> is intended to be returned rather than raised, replace the <code>raise</code> with <code>return NotImplemented</code>.
20+
</p>
2121
</recommendation>
2222
<example>
2323

2424
<p>
25-
In the example below, the method <code>wrong</code> will incorrectly raise a <code>TypeError</code> when called.
25+
In the following example, the method <code>wrong</code> will incorrectly raise a <code>TypeError</code> when called.
2626
The method <code>right</code> will raise a <code>NotImplementedError</code>.
2727
</p>
2828

@@ -34,6 +34,7 @@ The method <code>right</code> will raise a <code>NotImplementedError</code>.
3434
<references>
3535

3636
<li>Python Language Reference: <a href="https://docs.python.org/library/exceptions.html#NotImplementedError">The NotImplementedError exception</a>.</li>
37+
<li>Python Language Reference: <a href="https://docs.python.org/3/library/constants.html#NotImplemented">The NotImplemented constant</a>.</li>
3738
<li>Python Language Reference: <a href="https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types">Emulating numeric types</a>.</li>
3839

3940
</references>
Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* @name NotImplemented is not an Exception
3-
* @description Using 'NotImplemented' as an exception will result in a type error.
2+
* @name Raising `NotImplemented`
3+
* @description Using `NotImplemented` as an exception will result in a type error.
44
* @kind problem
55
* @problem.severity warning
66
* @sub-severity high
@@ -12,8 +12,17 @@
1212
*/
1313

1414
import python
15-
import Exceptions.NotImplemented
15+
import semmle.python.ApiGraphs
16+
17+
predicate raiseNotImplemented(Raise raise, Expr notImpl) {
18+
exists(API::Node n | n = API::builtin("NotImplemented") |
19+
notImpl = n.getACall().asExpr()
20+
or
21+
n.asSource().flowsTo(DataFlow::exprNode(notImpl))
22+
) and
23+
notImpl = raise.getException()
24+
}
1625

1726
from Expr notimpl
18-
where use_of_not_implemented_in_raise(_, notimpl)
27+
where raiseNotImplemented(_, notimpl)
1928
select notimpl, "NotImplemented is not an Exception. Did you mean NotImplementedError?"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
| exceptions_test.py:170:11:170:24 | NotImplemented | NotImplemented is not an Exception. Did you mean NotImplementedError? |
2-
| exceptions_test.py:173:11:173:24 | NotImplemented | NotImplemented is not an Exception. Did you mean NotImplementedError? |
2+
| exceptions_test.py:173:11:173:26 | NotImplemented() | NotImplemented is not an Exception. Did you mean NotImplementedError? |

0 commit comments

Comments
 (0)