David Scarlett
David Scarlett

Reputation: 3341

Misspelled __future__ import causes error later in script, not at import location

I discovered something odd, where I had accidentally misspelled printfunction as printfuncion in from __future__ import printfunction. This didn't give me an error at the location of the import statement, as I would have expected, but rather the import statement was seemingly ignored and an error was subsequently raised when I attempted to use the function print in a way that was incompatible with the statement form of print. This made the true cause of the error much less obvious than it otherwise would have been

Can anyone explain why the error is not picked up at the import line?

File 'bad_printfunc_import.py':

#!/usr/bin/env python

from __future__ import printfuncion

print('I will use the named param "sep" in this fuction call.',
      'That will cause an error, as with print as a statement',
      'rather than a function, these arguments will presumably be',
      'interpretted as a tuple rather than function arguments,',
      'and tuples can\'t have named elements.',
      sep='\n')

Error produced:

$ ./bad_printfunc_import.py 
  File "./bad_printfunc_import.py", line 10
    sep='\n')
       ^
SyntaxError: invalid syntax

Interestingly, if I remove the print call from the file, then I do get the error at the import line:

$ ./bad_printfunc_import.py 
  File "./bad_printfunc_import.py", line 3
    from __future__ import printfuncion
SyntaxError: future feature printfuncion is not defined

It does makes sense to me that it would generally report syntax errors ahead of an import failure, but that makes much less sense when the syntax being enforced is dependent on that __future__ import!

Upvotes: 2

Views: 396

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122182

from future ... imports are special in that they set flags that can affect two components: the parser and the compiler. Both parsing and compilation can fail if a flag is missing, but the parser won't report on misspelled names that the compiler might honour.

Disabling the print statement is a flag that affects the parser (together with the with_statement and unicode_literals flags), so the parser looks for just those flags. As such, because there is no print_function keyword found, the parser flag that disables the print statement is not set, and parsing fails, which gives you the syntax error.

Only if the compilation stage is reached will Python throw a syntax error for incorrect names:

>>> compile('''from __future__ import nonsuch; parser error here''', '', 'exec')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "", line 1
    from __future__ import nonsuch; parser error here
                                               ^
SyntaxError: invalid syntax
>>> compile('''from __future__ import nonsuch''', '', 'exec')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "", line 1
SyntaxError: future feature nonsuch is not defined

In theory the parser could report on invalid from __future__ names early, before the compiler gets to them, but that would complicate the parser further. As it stands, the parser already manually looks for those 3 special flags, while the compiler can just rely on the parsed AST. Having to check for all 7 possible names each time would add more complexity there for errors that are already caught by the compiler.

Upvotes: 4

Related Questions