ruff icon indicating copy to clipboard operation
ruff copied to clipboard

TCH rules require from __future__ import annotations

Open twoertwein opened this issue 3 years ago • 6 comments

The following does not work with 3.11.1 at runtime:

test.py

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from test_b import B

def test(x: B) -> B:
    return x

test_b.py

class B:
    ...
$ python test.py 
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    def test(x: B) -> B:
                ^
NameError: name 'B' is not defined

but it works when test.py contains from __future__ import annotations.

It might be good to either skip the TCH rules when from __future__ import annotations is not there or mention that this import needs to be added.

twoertwein avatar Jan 26 '23 18:01 twoertwein

Hmm yeah. flake8-type-checking has some things to say about that and additional rules. @sondrelg - I promise I'll stop pinging you, but anything else you'd say about the "right" way to handle this, based on your experience?

charliermarsh avatar Jan 26 '23 18:01 charliermarsh

Yeah this is correct for all Python version above 3.7 I believe. Ideally ruff should implement TC100, TC101, TC200, and TC201 as these are meant to complement the TC00[1,2,3] rule by telling you how to handle forward references.

What happens we when put an import inside a TYPE_CHECKING block (or any condition that is evaluated as False at runtime) is that the code path is not evaluated, so the import effectively doesn't happen at runtime. Since code outside the condition cannot reference something that isn't defined, we either wrap the undefined values in quotes or add a from __futures__ import annotations since this enables PEP563 behavior.

tl;dr: The TC00[1,2,3] need either the TC1* or TC2* range errors enabled (not both) to guide users into setting up their code in a valid way.

Sorry for not noticing this earlier. I should have warned you about this. And no worries about the pings - happy to help :+1:

sondrelg avatar Jan 26 '23 20:01 sondrelg

This section explains the concepts adequately, I hope: https://github.com/snok/flake8-type-checking#choosing-how-to-handle-forward-references

sondrelg avatar Jan 26 '23 20:01 sondrelg

So for now there is no way to turn TC1/TC2 in ruff?

RayJameson avatar Jan 30 '23 06:01 RayJameson

The code just has to be written I think @RayJameson. There shouldn't be any real blockers in place.

sondrelg avatar Jan 30 '23 07:01 sondrelg

Yup that's right -- we don't support those rules yet, only TC001 - TC005.

charliermarsh avatar Jan 30 '23 12:01 charliermarsh

I think this specific issue was actually a bug that we fixed around runtime requirements for annotations in function scopes.

charliermarsh avatar Feb 28 '23 22:02 charliermarsh

(That snippet no longer raises an error.)

charliermarsh avatar Feb 28 '23 22:02 charliermarsh

Sorry for necroposting, but I've been studying this for the last couple of hours and don't get it. Is from __future__ import annotation needed with these rules or not? If it is, why doesn't ruff add it?

Faithfinder avatar Jun 04 '24 14:06 Faithfinder