equinox icon indicating copy to clipboard operation
equinox copied to clipboard

Type hint error: eqx.field adds an Unknown type

Open HGangloff opened this issue 8 months ago • 4 comments

I have pylint complaining because eqx.field seems to add an Unknown type. For example, in the code below the specific use of eqx.field (and not dataclass.field) which I use because I want the attribute to be keyword only, causes the type of the attribute f to be changed to Unknown | AbstractCallableModule which results in a not-callable error later on.

import abc
from dataclasses import dataclass, field
import equinox as eqx

class AbstractCallableModule(eqx.Module):
    @abc.abstractmethod
    def __call__(self, *_, **__):
        pass

class Module1(eqx.Module):
    f: AbstractCallableModule

    def __call__(self, a):
        return self.f(a) # pylint does not complain

class Module2(eqx.Module):
    f: AbstractCallableModule = eqx.field(kw_only=True)

    def __call__(self, a):
        return self.f(a) # pylint complains about not-callable: type of f is Unknown | AbstractCallableModule

@dataclass
class Module3:
    f: AbstractCallableModule = field(kw_only=True)

    def __call__(self, a):
        return self.f(a) # pylint does not complain

I don't get what is happening here. I have python==3.11.11, pylint==3.3.6 and equinox 0.11.11

Thanks

HGangloff avatar May 01 '25 15:05 HGangloff

Thanks for the report ! Unfortunately I'm afraid I can't duplicate this, using python=3.11.8, pyright==1.1.399 and equinox==0.11.11.

FWIW I am running pyright via pip install pyright; pyright file.py.

patrick-kidger avatar May 01 '25 17:05 patrick-kidger

Ok I was wrong, the error message comes from pylint==3.3.6. Edited the original post

HGangloff avatar May 02 '25 08:05 HGangloff

But still, pyright in strict mode complains that Type of f is unknown specifically for Module2: f: AbstractCallableModule = eqx.field(kw_only=True)

HGangloff avatar May 02 '25 08:05 HGangloff

Right, pylint is probably in the wrong here and failing to notice our usage of dataclass_transform. (I'd suggest switching to ruff anyway, it's by far the more common and performant choice.)

For pyright in strict mode, I've just fiddled around a bit I think adding a return Any type annotation to eqx.field might resolve things? Happy to take a PR if that also fixes things for you too.

patrick-kidger avatar May 03 '25 07:05 patrick-kidger