Skip to content
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

Variables declared as Type[Foo] doesn't support operators from Foo's metaclass #4789

Closed
dgelessus opened this Issue Mar 24, 2018 · 3 comments

Comments

Projects
None yet
3 participants
@dgelessus
Copy link
Contributor

dgelessus commented Mar 24, 2018

When a variable's type is declared as Type[Foo], and Foo has a metaclass that defines an operator, attempting to use that operator on the variable falsely causes an error. The metaclass methods can be used; only operators are broken. The bug does not happen when the variable's type is inferred (var = Foo instead of var: Type[Foo] = Foo).

I'm using Python 3.6.4 and the current mypy version from the repo (0.580-dev-80a9b8f8e362902a93606ea0aabf9c18184fef3e) with no special command-line flags.

Example code demonstrating the false error:

from typing import Type

class CDataMeta(type):
    def __mul__(self, other: int) -> str:
        return "foo"
    
    def __rmul__(self, other: int) -> str:
        return "rfoo"
    
    def method(self) -> None:
        pass

class CData(metaclass=CDataMeta):
    pass

foo = CData
bar: Type[CData] = CData

def get_cdata_type() -> Type[CData]:
    return CData

# Correct behavior when the operand's type is inferred:
CData * 4  # No error
foo * 4  # No error

# Incorrect behavior when the operand's type is explicitly declared:
bar * 4  # error: Unsupported operand types for * ("Type[CData]" and "int")
get_cdata_type() * 4  # error: Unsupported operand types for * ("Type[CData]" and "int")

# Correct behavior - all of the following work:
CData.method()
foo.method()
bar.method()
get_cdata_type().method()

# Correct behavior - all of the following cause errors:
CData.nope()
foo.nope()
bar.nope()
get_cdata_type().nope()

This is a very simplified version of the Typeshed ctypes stub code (see python/typeshed#1983).

@ilevkivskyi

This comment has been minimized.

Copy link
Collaborator

ilevkivskyi commented Mar 24, 2018

The difference between these two:

foo = CData
bar: Type[CData] = CData

is that the first creates a type alias, while the second defines a variable. As a result, the type of foo expression in runtime context is Callable with the constructor signature, while the type of bar is just Type[...]. So indeed only Type[...] is problematic with operators like __add__, __mul__ etc., other types work OK.

@dgelessus

This comment has been minimized.

Copy link
Contributor Author

dgelessus commented Mar 24, 2018

OK - does that mean that using metaclass methods/operators on a Type[...] variable is not supported? The relevant PEP 484 section makes it sound like Type[...] only supports methods defined by type. However mypy seems to support calling custom metaclass methods on Type[...], and detects when nonexistant methods are called (that's what I was testing with the last 8 calls in my test code), so it would make sense for operators to be supported the same way.

@JukkaL

This comment has been minimized.

Copy link
Collaborator

JukkaL commented Mar 26, 2018

OK - does that mean that using metaclass methods/operators on a Type[...] variable is not supported?

The lack of support for operators is a bug in the implementation of Type[...]. Operators should be supported by mypy.

@dgelessus dgelessus referenced this issue Mar 26, 2018

Merged

Fix some issues in ctypes (fixes #1983) #1986

11 of 11 tasks complete

ilevkivskyi added a commit that referenced this issue Mar 29, 2018

Fix operator access on Type[...] (#4823)
Fixes #4789

The idea is straightforward add overlooked elif. A better long-term solution
may be to refactor has_member to use checkmember.analyze_member_access.

I use pythoneval tests because the original problem only appears currently with
full stubs (apparently because int doesn't have operator methods in fixtures).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.