Skip to content

"Invalid type" when using class attribute as type variable. #7052

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
feluxe opened this issue Jun 24, 2019 · 5 comments
Closed

"Invalid type" when using class attribute as type variable. #7052

feluxe opened this issue Jun 24, 2019 · 5 comments

Comments

@feluxe
Copy link

feluxe commented Jun 24, 2019

Are you reporting a bug, or opening a feature request?

A bug I guess. Please excuse me if I'm missing something here.

Code to reproduce the issue:

@dataclass
class Column:
    name: str


class Pg:
    Column = Column

pg = Pg()

@dataclass
class SearchToken:
    column: pg.Column

What is the actual behavior/output?

Mypy marks the last line as an error:

Invalid type mypackage.mymodule.pg

What is the behavior/output you expect?

Mypy not complaining about the last line or a better error message, that guides me somewhere to solve the given scenario. I feel kinda lost with this right now.

What are the versions of mypy and Python you are using?
Python 3.7.3
mypy 0.710

Do you see the same issue after installing mypy from Git master?
I couldn't get this to work with pipenv.

What are the mypy flags you are using?
I don't use any.

@ilevkivskyi
Copy link
Member

Accessing nested class on an instance is not considered statically decidable. You should instead use it as class attribute:

@dataclass
class SearchToken:
    column: Pg.Column

@ilevkivskyi
Copy link
Member

(For the better error message we already have an issue #4030)

@ilevkivskyi
Copy link
Member

ilevkivskyi commented Jul 4, 2019

Oh wait sorry, I thought it is a nested class, but it is actually a variable, this is even more tricky. You can try Column = Union[Column] to force it to be an alias, but after all, why can't you just use Column directly?

@feluxe
Copy link
Author

feluxe commented Jul 4, 2019

Thanks for your reply!

You can try Column = Union[Column] to force it to be an alias

Do you mean like this:

class Pg:
    Column = Union[Column]

?

but after all, why can't you just use Column directly?

My example is a simplified version of the actual code. The original version was rather like this:

postgres.py

@dataclass
class Column:
    name: str
    # More stuff going on here

class Pg:
    Column = Column
    # More stuff going on here

    async def connect(self):
        self.pool = await init_pg()

pg = Pg()

The pg instance exposes everything from the postgres module that is important to other modules within the porject. Other modules within the project conveniently import it like this:

from postgres import pg

and have everything they need.

That's why I ran into the following issue in search.py:

search.py

from postgres import pg

@dataclass
class SearchToken:
    column: pg.Column
    # More stuff going on here

I fixed the issue by moving all pg types (Column, PgInt, etc.) into another module pgtype.py and ended up with imports like this:

from postgres import pg, pgtype

But now I have to work with pg and pgtype everywhere instead of just pg, which is less convenient. :-)

@ilevkivskyi
Copy link
Member

Do you mean like this: ...

Yes, exactly, and then you should be able to use it as Pg.Column in annotations.

But now I have to work with pg and pgtype everywhere instead of just pg, which is less convenient

Well, some patterns that come from dynamic typing world are sometimes not very reasonable in the static world. Some things can be mitigated by writing a mypy plugin if this is really important (I think someone tried to write a plugin for gino, that uses a similar pattern extensively).

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

2 participants