pythonpython-typingpython-3.10flake8

Flake8 gives F832 Undefined Name despite using "from __future__ import annotations"


I have this pyi file.

from __future__ import annotations
import datetime


class Payment:
    amount: float = ...
    date: datetime.date = ...

    def set_amount(self: Payment, amount: float = Amounts.Null):
        ...

    def get_amount(self: Payment) -> float:
        ...

    def get_date(self: Payment) -> datetime.date:
        ...


class Amounts:
    Null: float = ...

Using from __future__ import annotations helps remove the F821 undefined name 'Payment' warnings for the self arguments.

However, flake8 still shows F821 undefined name 'Amounts'. Can this warning be fixed somehow (without disabling F821 entirely)? Or it this a bug perhaps?


Note, I am using flake8 4.0.1 (mccabe: 0.6.1, pycodestyle: 2.8.0, pyflakes: 2.4.0) on Python 3.10.0.


Solution

  • the error is not wrong:

    $ python3 t.pyi
    Traceback (most recent call last):
      File "t.pyi", line 5, in <module>
        class Payment:
      File "t.pyi", line 9, in Payment
        def set_amount(self: Payment, amount: float = Amounts.Null):
    NameError: name 'Amounts' is not defined
    

    __future__ annotations defers annotations but you've got a default value (which is not an annotation!) referring to a class later in the file

    one option is a simple reordering:

    from __future__ import annotations
    import datetime
    
    
    class Amounts:
        Null: float = ...
    
    
    class Payment:
        amount: float = ...
        date: datetime.date = ...
    
        def set_amount(self: Payment, amount: float = Amounts.Null):
            ...
    
    # ...
    

    even better is to omit the default value entirely, since it does nothing in a pyi (or stub function):

    from __future__ import annotations
    import datetime
    
    
    class Payment:
        amount: float = ...
        date: datetime.date = ...
    
        def set_amount(self: Payment, amount: float = ...):
    
    # ...
    

    note also that your function is subtly incorrect -- right now a type checker will interpret set_amount as -> Any because you omit the return value, the correct thing to do there is -> None

    the other route you can take is to ignore the errors via # noqa, per-file-ignores, or other means -- though that's probably not what you want to do since the code as-is is broken


    disclaimer: I currently maintain flake8