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

Attempt to reproduce #91 #92

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mypy-zope.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[mypy]
namespace_packages=True
warn_unreachable=True
plugins=mypy_zope:plugin
8 changes: 8 additions & 0 deletions src/mypy_zope/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Type as PyType
from typing import cast

from mypy.typestate import type_state
from mypy.types import (
Type,
Instance,
Expand Down Expand Up @@ -722,6 +723,13 @@ def _apply_interface(self, impl: TypeInfo, iface: TypeInfo) -> None:
if promote not in impl._promote:
impl._promote.append(promote)

# Remember implementation as a subtype of an interface. HACK: we are
# writing to a global variable here, so potentially this might be a
# memory leak. Needs testing with a large codebase.
asmpt = (Instance(impl, []), promote)
type_state.get_assumptions(False).append(asmpt)
type_state.get_assumptions(True).append(asmpt)


def plugin(version: str) -> PyType[Plugin]:
return ZopeInterfacePlugin
31 changes: 31 additions & 0 deletions tests/samples/dmr_unreachable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import Optional

from zope.interface import Interface, implementer


class IFoo(Interface):
pass


@implementer(IFoo)
class BaseFoo:
pass


class ChildFoo(BaseFoo):
pass
Comment on lines +15 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the "important" difference between this test case and isinstance_impl. On line 26 below we are asserting that something of type IFoo could be an instance of a subclass of a class implementing IFoo.

In isinstance_impl line 20, we do the same but without the additional subclass.



class IFooFactory(Interface):
def build() -> Optional[IFoo]:
pass


def build_and_use_foo(client_factory: IFooFactory) -> None:
client_protocol = client_factory.build()
assert isinstance(client_protocol, ChildFoo)
print("Hello")


"""
"""
29 changes: 29 additions & 0 deletions tests/samples/isinstance_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import Optional
from zope.interface import implementer, Interface


class IFoo(Interface):
...


@implementer(IFoo)
class MyFoo:
...


def make_foo() -> Optional[IFoo]:
return MyFoo()


x = make_foo()
reveal_type(x)
assert isinstance(x, MyFoo)

# The code below should not be considered unreachable
print("hello")

"""
<output>
isinstance_impl.py:19: note: Revealed type is "Union[__main__.IFoo, None]"
</output>
"""
1 change: 1 addition & 0 deletions tests/test_samples.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def test_samples(samplefile, mypy_cache_dir):
opts.show_traceback = True
opts.namespace_packages = True
opts.hide_error_codes = True
opts.warn_unreachable = True
opts.plugins = ['mypy_zope:plugin']
# Config file is needed to load plugins, it doesn't not exist and is not
# supposed to.
Expand Down