Typing: Tweak scope of `# type: ignore` in PEP 484

Created on 5 Oct 2016  路  9Comments  路  Source: python/typing

PEP 484 currently says:

A # type: ignore comment on a line by itself disables all type checking for the rest of the file.

I think that's excessive. It should probably be limited to the current indented block, e.g.

if blargh():
    # type: ignore
    1 + 'a'  # No error here
2 + 'b'  # Should be an error

All 9 comments

I agree, while placing #type: ignore at top indentation level would prohibit type checking for the rest of the file.

Agreed.

Refining the extent to the enclosing scope (module/function/class) makes sense, but any narrower might be tricky.
Is it meaningful to infer types with a # type: ignore block?
What about

if cond:
    # type: ignore
    1 + 'a'  # No error here
else:
    1 + 'a'  #Is this an error?

I think that in Mark's example the second 1 + 'a' (in the else block) should not be an error. That seems easy.

The trickier bit is whether assignments still get inferred:

if cond:
    # type: ignore
    x = 42
else:
    x = 'z'

What's the type of x here? Union[int, str]? If this would work the same as just adding an inline # type: ignore to each line of the block, that's what it would mean, and that seems a fine rule.

if-else may be relatively easy but what about try-except-finally?

What is the motivation for this?
I can see why I might want the checker to ignore a whole function. I struggle to think of a case where I might want it to ignore just a part of a function.

I would definitely like to ignore a conditional block full of platform-specific imports. (E.g. if I have no stubs for them.)

I wouldn't want to have a syntax where a # type: ignore placed anywhere in a function had the effect of ignoring the entire function body.

The motivation is to define a syntax that is easy to understand and syntactically orthogonal. Given that we have at least two use cases (ignore a while function, ignore a branch of a conditional), the best approach seems to be to define the scope of # type: ignore as the remainder of the current "block" as determined by indentation. A block is a well-understood syntactic construct in Python, and used in many places. So whenever you see a block containing # type: ignore you will be able to understand the scope of that directive.

I'm not sure if it's abusing it a bit, but what about making no_type_check also a context manager? In that way you can write:

with no_type_check():
    'a' + 1

Here the block scope is very obvious to a reader (because context managers are conceptually tied to a block). I think this eliminates all ambiguity about else branches or try/except being covered or not. OTOH it adds an indentation level, and it's mixing a bit with a run-time concept like context managers with something that is very not run-time.

# type: ignore is nice in that it has no runtime overhead. It can be important in a tight loop or in a function that gets called a lot.

I'd stay away from a context manager -- people expect runtime behavior from
those.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mitar picture mitar  路  5Comments

zsluedem picture zsluedem  路  3Comments

ilevkivskyi picture ilevkivskyi  路  8Comments

gvanrossum picture gvanrossum  路  5Comments

JelleZijlstra picture JelleZijlstra  路  6Comments