Unexpected indentation error, or, is it likely the interpreter is wrong?

Hello all,

I’ll start by saying I know it’s almost certain it’s me, but when I test a program I’m writing it’s exhibiting some strange behaviour that honestly has me wondering if it’s my interpreter that is misbehaving. The first issue is an unexpected indentation error that I have posted below. I’m not posting the entire program just because it’s a bit too long, but if there is somewhere more appropriate I can do that then please let me know.

### select the OxygenOS update file ###

if match_obj.group('FILE') != None:

    if access(match_obj.group('FILE'), F_OK) and access(match_obj.group('FILE'), R_OK):
        update_file = match_obj.group('FILE')
        print('\nUsing update file \'' + split(update_file)[-1] + '\' passed on command line')
    else:
        print(('\nWARNING: the given update file path is invalid, OR;\n'
               'you do not have read permission for the given file\n\n'
               '* verify the argument to --file is a valid file path\n'
               '* ensure your user has permission to read the file'))
        exit(1)

else:

    print('\nSelecting the most recent update file...', end='')

    update_files = []

    for dirpath, _, filenames in walk(expanduser('~')):
        for filename in filenames:
            if match('^OnePlus6TOxygen.*\.zip$', filename):
                update_files += [join(dirpath, filename)]
    
    if not update_files:
        print('\n\nWARNING: no OxygenOS OTA update files were found;\nupdate files must be located under', home_var)
        exit(1)
    
    ### if more than one update file was found, determine the most recent version according to the timestamps ###
    
    if len(update_files) > 1:
        most_recent_timestamp = 0
        for i in update_files:
            timestamp = int(split(i)[-1].split('_')[5])
            if timestamp > most_recent_timestamp:
                most_recent_timestamp = timestamp
                update_file = i
    else:
        update_file = update_files[0]

    print('\nSelected update file "' + split(update_file)[-1] + '"')

When I run the program I get the following error:

  File "/home/Slurms_MacKenzie/top_level/scripts/python/opflash_v1/opflash_v1.01.py", line 177                                                      
    print('\nSelected update file "' + split(update_file)[-1] + '"')                                                                        
                                                                    ^                                                                       
IndentationError: unindent does not match any outer indentation level

To my eye, the final print statement is correctly indented and contained within the else: clause of the outermost if statement. I know it’s not a very exciting problem but I’d appreciate if someone could cast their eye over it and see if they can spot any error.

Can’t see anything wrong in the snippet you posted. But indentation errors are finicky; the actual error may be (much) higher up than the reported line.

Two thoughts:

  1. Are you mixing tabs and spaces?
  2. Use an automatic code formatter like black and never have to worry about this again.

I believe I probably am mixing tabs and spaces. I was previously using IDLE but I recently made the transition to vim; do you think it might be the case that vim doesn’t convert a tab to four spaces? (for what it’s worth, the tab is four terminal columns of white-space). Also my vim was compiled with python3 support, if that matters.

I’ll go back and see what the situation is with tabs and spaces.

EDIT: from what I can tell, my vim does convert a tab to four spaces. What might be significant is that when I try to move the text cursor over to the far left margin anywhere in the outermost if clause, it lets me; when I try to do the same in the accompanying else clause it will only let me go as far left as the terminal column before the first level of indentation, if that makes sense. This is with the sole exception of the line with the final print statement, which lets me move the cursor all the way over to the left margin, strange…

Unfortunately black cannot fix IndentationError (or any kind of SyntaxError), it has to parse the file before it can reformat, so the code should already be valid syntax.

Here you have to rely on a good editor that can show whitespace characters and do the fix manually or maybe with editor macros.

Fair, but by automatically running black every time you save (i.e. every 0.5 seconds), you at least won’t have to worry about something like this cropping up down the line.

@abessman @saaketp Thanks you two, I solved it. I don’t actually know what the problem was, but I went back and erased all the leading white-space before the lines in the else clause and manually entered the correct number of spaces.

I suspect it’s something to do with vim, maybe I changed a configuration item without knowing, I’m not sure. but I feel like it will crop up again and then I’ll realise what causes it. It could be something to do with spaces vs tabs, as you mentioned abessman.

Thanks again!

That is how normally vi(m) behaves when the first character is a tab. Vim positions cursor to the rightmost position of a character you are at.

Other ways how to recognize tabs:


In Python never mix spaces and tabs. In theory you can do that in practice you will make a code which is easy to break, hard to understand and maintain.

1 Like

Thanks, interestingly I initially tried removing all of the (what I now know were) tabs and replacing them with four spaces, but what I think happened is because I missed just one tab, something triggers vim to change them all back to tabs again. Only when I thoroughly removed all the tabs did all the sets of four spaces remain.

That’s only what was kind of apparent to me, but I didn’t test it very vigorously. Thanks for the resources, they will be very useful next time it happens!

Hmm, it makes it less likely. But a bad indent will inherently prevent
black reformatting the code.

My personal problem with black is that it changes the values in the
code. I’m looking at you, black-docstring-mangler. I use yapf in my
personal code.

Cheers,
Cameron Simpson cs@cskk.id.au

I do that to tabbed input by piping the whole file through detab
(personal script, but there are an number of utlities which will expand
tabs).

My vim settings include set expandtab, which expands TABs to spaces.

That way I can use the TAB key to position the indents, but the file
ends up with spaces.

There are 2 schools of though here. Im in the school which holds that
I’ll always use spaces, and reformat using a code formatter if I need to
change what that means. The other camp says that TABs should express
one indent, and the editor tabwidth setting can be used by anyone’s
personal editor to present the indentation at whatever scale they find
helpful. The former is pragmatic, and the latter is semanticly/structurally sound.

For me, there are too many situations where a TAB will be rendered as eg
4 or 8 spaces (eg in the terminal versus in this editor versus in that
editor etc etc) that I’d rather just use spaces and get consistent
behaviour everywhere.

I think everyone’s on the same page with mixing TABs and spaces: don’t
do that! (In the domain of code indentation.)

Cheers,
Cameron Simpson cs@cskk.id.au

The IDLE Format menu includes ‘Untabify region’ to convert tabs to a specified number of spaces. Run → Run module checks for tab/space/indent problems before calling compile().