2

I had in my code a bug like this:

if 'char' or 'CHAR' in dt:
    foo = 'ch'

and it took me a while to debug it. If I am correct, the first operand always evaluates to true, which causes the body of the if statement to always execute.

In C++ I would get a warning in some of these cases, making the annihilation of such bugs easy.

Is there any way that I can get Python warn me about these situations, or not (because it gets interpreted or something)?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • It's a string @raj, updated. It should be the data types, but you know users . . . – gsamaras Oct 10 '18 at 08:27
  • Get a warning from who? The python interpreter? Your python IDE? A tool made specifically to detect this kind of thing? – Aran-Fey Oct 10 '18 at 08:28
  • Static analysis tools might be able to figure these out, but the error is very obvious. – Matthieu Brucher Oct 10 '18 at 08:28
  • @Jean PyCharm does not seem to catch this particular problem. – deceze Oct 10 '18 at 08:29
  • It was me in the past @Jean-FrançoisFabre. I should tell myself something! Pycharm might be a good solution, if it really does the trick, Aran-Fey for example. Matthiueu, sorry.... Jean-Francois, maybe post an answer? – gsamaras Oct 10 '18 at 08:29
  • @raj It's pretty irrelevant what `dt` is, the error is (somewhat) obvious either way. – deceze Oct 10 '18 at 08:30
  • 1
    @deceze in large code files, even the simplest of things can be hard to get traced some times. Machines can help fight my human nature. =) – gsamaras Oct 10 '18 at 08:31
  • 1
    FWIW, `'char' or anything` evaluates to `'char'` since a non-empty string is True-ish, and `anything` isn't evaluated (eg if it's a function it's not called), since `or` short-circuits. – PM 2Ring Oct 10 '18 at 08:32
  • @PM2Ring correct, thanks. But even if it didn't short-circuit, it would still behave the same. We have this [mechanism in C as well](https://stackoverflow.com/questions/26716255/why-does-this-program-print-forked-4-times/26716300#26716300), but that's beside the point. – gsamaras Oct 10 '18 at 08:35
  • 2
    @PM2Ring I think he knows. It's just a typo, but once it's coded & lost in the code, it's hard to debug – Jean-François Fabre Oct 10 '18 at 08:36
  • 1
    So anyone can tell op use which tool can get a warning, `pylint` or `flake8`? Seems all cannot show a warning. – atline Oct 10 '18 at 08:36
  • @lagom to relax a bit the question, anything would do, from a warning, to an error. I just would like a sign... =) PS: A negative answer would also be appreciated, since it would make me stop searching. I would love to get feedback from the downvoter, and then improve the question, or even delete it, if needed. – gsamaras Oct 10 '18 at 08:37
  • @Jean-FrançoisFabre Sure, I was just elaborating because "the first operand always evaluates to true" doesn't quite explain what's going on. – PM 2Ring Oct 10 '18 at 08:41
  • @gsamaras Understood. FWIW, I learned C a few decades before I learned Python. I agree that it is a tricky thing to debug, but as with any language, you gradually learn to look for "likely suspects" like this. I think it would be tricky for an automatic tool to find this sort of thing and not get too many false positives. – PM 2Ring Oct 10 '18 at 08:42

1 Answers1

2

It's difficult not to emit false positives in the general case. Imagine this code:

if list_empty or x in my_list:

this is perfectly valid to any human because list_empty is probably a boolean. Now with:

if number1 or number2 in my_list:

A (woken up :)) human sees the error immediately (because the names are similar, and usually identify numbers not conditions, same for strings with if name1 or name2 in my_list:), but that would require the static analyser to know the type for sure.

And even in those "trivial" cases, who knows if the programmer didn't want to test if number1 is zero or name1 is empty to proceed to the next test?

Type annotations may help, I didn't test all tools out there to give you a positive answer but the dynamic nature of python makes it very difficult to be sure of the intent of the programmer, and what's worth an analyser program with emits a ton of false positives?

For string & integer/float literals this construct is probably a mistake, so I wrote a lousy static analyzer with regexes. Cheap and if it yells, you're very likely with a faulty line (standalone example here which self-analyses itself):

dt=[]
if 'char' or 'CHAR' in dt:
    foo = 'ch'
if 12.0 and 45 in dt:
    foo = 'ch'

import re
infamous_bug = re.compile("if\s+(['\"].*?['\"]|[\d\.]+)\s+(or|and)")
with open(__file__) as f:
    for line in f:
        if infamous_bug.search(line):
            print("GOTCHA {}".format(line.rstrip()))

outputs:

GOTCHA if 'char' or 'CHAR' in dt:
GOTCHA if 12.0 and 45 in dt:
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219