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

Crash when overriding field as property/method on frozen derived class #8334

Closed
jjlee opened this issue Jan 26, 2020 · 3 comments · Fixed by #13531
Closed

Crash when overriding field as property/method on frozen derived class #8334

jjlee opened this issue Jan 26, 2020 · 3 comments · Fixed by #13531

Comments

@jjlee
Copy link

jjlee commented Jan 26, 2020

I see this on python/mypy master (41b40aa) and Python 3.7.5.

Following on from #7535 (fixed recently by @msullivan), this triggers another crash (really just adding the frozen=True from my example on that bug report, though I also dropped the args to field since I realised I could):

from dataclasses import dataclass, field

@dataclass
class Base:
    foo: bool = field()

@dataclass(frozen=True)
class Derived(Base):
    @property
    def foo(self):
        pass

Traceback (seems slightly different from #6715 -- the assertion here is in method _freeze, not method collect_attributes):

$ mypy --show-traceback /home/me/minimal3.py
/home/me/minimal3.py:10: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.rtfd.io/en/latest/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.770+dev.41b40aa4fc7cdeb32f5ee4fec97f5379ebbe795d
Traceback (most recent call last):
  File "/home/me/env/3/moving-target/bin/mypy", line 11, in <module>
    load_entry_point('mypy', 'console_scripts', 'mypy')()
  File "/home/me/dev/mypy/mypy/__main__.py", line 8, in console_entry
    main(None, sys.stdout, sys.stderr)
  File "/home/me/dev/mypy/mypy/main.py", line 89, in main
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File "/home/me/dev/mypy/mypy/build.py", line 166, in build
    sources, options, alt_lib_path, flush_errors, fscache, stdout, stderr, extra_plugins
  File "/home/me/dev/mypy/mypy/build.py", line 234, in _build
    graph = dispatch(sources, manager, stdout)
  File "/home/me/dev/mypy/mypy/build.py", line 2631, in dispatch
    process_graph(graph, manager)
  File "/home/me/dev/mypy/mypy/build.py", line 2938, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/home/me/dev/mypy/mypy/build.py", line 3031, in process_stale_scc
    mypy.semanal_main.semantic_analysis_for_scc(graph, scc, manager.errors)
  File "/home/me/dev/mypy/mypy/semanal_main.py", line 77, in semantic_analysis_for_scc
    process_top_levels(graph, scc, patches)
  File "/home/me/dev/mypy/mypy/semanal_main.py", line 202, in process_top_levels
    patches)
  File "/home/me/dev/mypy/mypy/semanal_main.py", line 330, in semantic_analyze_target
    active_type=active_type)
  File "/home/me/dev/mypy/mypy/semanal.py", line 363, in refresh_partial
    self.refresh_top_level(node)
  File "/home/me/dev/mypy/mypy/semanal.py", line 374, in refresh_top_level
    self.accept(d)
  File "/home/me/dev/mypy/mypy/semanal.py", line 4682, in accept
    node.accept(self)
  File "/home/me/dev/mypy/mypy/nodes.py", line 939, in accept
    return visitor.visit_class_def(self)
  File "/home/me/dev/mypy/mypy/semanal.py", line 1014, in visit_class_def
    self.analyze_class(defn)
  File "/home/me/dev/mypy/mypy/semanal.py", line 1091, in analyze_class
    self.analyze_class_body_common(defn)
  File "/home/me/dev/mypy/mypy/semanal.py", line 1100, in analyze_class_body_common
    self.apply_class_plugin_hooks(defn)
  File "/home/me/dev/mypy/mypy/semanal.py", line 1146, in apply_class_plugin_hooks
    hook(ClassDefContext(defn, decorator, self))
  File "/home/me/dev/mypy/mypy/plugins/dataclasses.py", line 369, in dataclass_class_maker_callback
    transformer.transform()
  File "/home/me/dev/mypy/mypy/plugins/dataclasses.py", line 182, in transform
    self._freeze(attributes)
  File "/home/me/dev/mypy/mypy/plugins/dataclasses.py", line 355, in _freeze
    assert isinstance(var, Var)
AssertionError: 
/home/me/minimal3.py:10: : note: use --pdb to drop into pdb
@anis-campos
Copy link

anis-campos commented Jun 14, 2021

Is there any workaround that would make this less of a crash but more of a warning ? warning that could therefore be ignore just like the others ones ?

It's so sad no being able to properly override inherited properties with @property, it's becomes very difficult to impose immutability of the dataclasses without some cumbersome workaround via __post_init__ and object.setattr

@JukkaL
Copy link
Collaborator

JukkaL commented Aug 24, 2022

In #8976 there was a similar-looking crash when overriding a frozen attribute with a method:

from dataclasses import dataclass


@dataclass(frozen=True)
class Foo:
    attr: int


@dataclass(frozen=True)
class Bar(Foo):
    def attr(self) -> int:
        return 1

@JukkaL JukkaL changed the title Traceback with overridden field property on frozen derived class Crash when overriding field as property/method on frozen derived class Aug 24, 2022
@anis-campos
Copy link

Isn't this related to #13475 ? Well I guess not completely, as for a frozen dataclass, a read-only property should be enough

Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Aug 27, 2022
This pull request:

1.  Fixes python#8334. Overriding a dataclass attribute with a method or
    property now results in an error message, not a crash.

    (Overriding an attribute with a non-attribute at runtime will
    result in either inconsistent behavior or an exception, so
    I think unconditionally disallowing this is fine.)

2.  Makes mypy report an error if you try subclassing a frozen
    dataclass with a non-frozen one or vice versa. Attempting to
    do this subclassing at runtime will raise a TypeError.
JukkaL pushed a commit that referenced this issue Aug 27, 2022
This pull request:

1.  Fixes #8334. Overriding a dataclass attribute with a method or
    property now results in an error message, not a crash.

    (Overriding an attribute with a non-attribute at runtime will
    result in either inconsistent behavior or an exception, so
    I think unconditionally disallowing this is fine.)

2.  Makes mypy report an error if you try subclassing a frozen
    dataclass with a non-frozen one or vice versa. Attempting to
    do this subclassing at runtime will raise a TypeError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants