Skip to content

Do we need a standard way of silencing checkers? #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JukkaL opened this issue Oct 16, 2014 · 10 comments
Closed

Do we need a standard way of silencing checkers? #16

JukkaL opened this issue Oct 16, 2014 · 10 comments

Comments

@JukkaL
Copy link
Contributor

JukkaL commented Oct 16, 2014

It may be useful to have a way of saying "don't complain about this type error; trust me, I know what I'm doing". For example, consider this code:

def foo(f: Function[...]) -> None:
    f._attr_ = True   # Error? But what if this is intentional?

A type checker would probably not allow assigning to an attribute of a function. However, sometimes programmers do this, and it works for user-defined functions. Maybe we could have a standard way of asking the type checker to shut up and ignore this particular warning only.

If we don't specify this in the PEP, there could end up being multiple tool-specific ways of doing this.

Apparently pylint supports something like this:

# pylint: disable=fixme

Hack also has something like this (example copied from Hack docs):

<?hh
function unsafe_foo(int $x, int $y): int {
  if ($x > $y) {
    // UNSAFE
    return "I am not checked by the type checker"; // Covered by UNSAFE
  }
  return 34; // NOT covered by UNSAFE
}

Link to relevant Hack docs: http://docs.hhvm.com/manual/en/hack.modes.unsafe.php

@ambv
Copy link
Contributor

ambv commented Jan 7, 2015

The Hack approach would basically be:

with typing.off:
  ...

The pylint approach has much more granularity but requires unique IDs to all checks.

@gvanrossum
Copy link
Member

I like the simple with-statement. I think it is possible to write something that is both a decorator and a context manager. IIRC the unittest.mock package does this, so perhaps we could use the same name. When used as typing.off the cute name is fine; but after "from typing import off" it's too short IMO. (It turns off what?)

@JukkaL
Copy link
Contributor Author

JukkaL commented Jan 8, 2015

The with statement is somewhat slow in CPython (the same applies to things like List[int] and Undefined(...)) and introduces an extra block nesting level, which makes code more difficult to read.

We could also have a comment that disables/enables all errors:

# typing: off
1 + 'x'  # don't report an error
# typing: on
1 + 'x'  # report an error

The comment should probably only extend until the end of the block that introduced it:

if foo:
    # typing: off
    1 + 'x'   # don't report an error
1 + 'x'  # report an error

@gvanrossum
Copy link
Member

Hm. I'm not so keen on introducing more magic comments. See #35

@gvanrossum
Copy link
Member

So we're introducing magic comments, but we might want to have something for stub modules to declare that a module exports absolutely anything: https://mail.python.org/pipermail/python-ideas/2015-January/031381.html

@JukkaL
Copy link
Contributor Author

JukkaL commented Jan 28, 2015

Mypy has a related concept for classes as an enhancement proposal. It would allow any attribute that's not explicitly defined to be accessed with type Any, but explicitly defined attributes could still have non-Any types. Obviously this can be implemented by defining dummy __getattr__ and __setattr__, but having special construct this may be less ugly and more explicit. For example:

from typing import Dynamic

class A(Dynamic):
    x = 0

a = A()
a.x = ''  # Error, x is an integer
x.y = ''  # Okay, y is not explicitly defined so it defaults to Any

Here are more syntax ideas:

@dynamicclass
class A: ...

@openclass
class A: ...

class A:
    * = Undefined(Any)  # Based on Guido's idea

I like the idea of having something like this, both for modules and classes. It would make it easy to define partial, work-in-progress stubs with static types only for the most commonly used features, and everything else would default to Any.

@gvanrossum
Copy link
Member

There's probably a mypy task left here, and there's a TODO for the class decorator in my typing.py, but the decision is made so I'm closing this:

  • To disable for the rest of the file:
# type: ignore
  • To disable per class or method, use @no_type_check

@JukkaL
Copy link
Contributor Author

JukkaL commented Mar 28, 2015

The PEP draft is still somewhat unclear on this. Here's how I'd like # type: ignore to work.

Case 1: ignore until end of block

if c:
    # type: ignore
    x.foo = 1  # don't complain about this
x.bar = 2  # potentially complain about this

Case 2: ignore until end of file (special case of 1)

x.foo = 1  # this is type checked

# type: ignore

x.bar = 2 # this is ignored by the type checker
...

Case 3: ignore single line (comment on a non-empty line)

x.foo = 2  # type: ignore      # no complaints

x.bar = 3  # this is type checked

Case 4: ignore import statement

If we ignore an import statement, don't try to type check the imported module and don't complain if we can't find it. Give type Any to any imported names:

from foo import x  # type: ignore    # should this be # type: Any?
import foo2  # type: ignore

x.bar()   # okay, x has type Any
foo2.bar()  # okay, foo2 has type Any

@refi64
Copy link

refi64 commented Mar 29, 2015

So, is there still no way to ignore a small chunk of text? This would definitely work:

x = 1
if True:
    # type: ignore
    # this always runs and never gets type checked
    x = 'abc'

but it feels ugly to me. I would like some kind of fake context manager:

with ignore_type:
    ...

but that would probably have speed issues.

@gvanrossum
Copy link
Member

But how often do you really need that? Have you run into examples where you need this or are you just musing on potential use cases? The context manager feels too heavy to me (though if we want it, we could probably make the no_type_check decorator also act as a context manager, similar to some unittest decorators). Why couldn't you use x = 'abc' # type: Any?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants