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

frozen dataclass inheritance is not strictly checked in multiple inheritance #109409

Closed
Batman-q96 opened this issue Sep 14, 2023 · 5 comments
Closed
Assignees
Labels
type-feature A feature request or enhancement

Comments

@Batman-q96
Copy link

Batman-q96 commented Sep 14, 2023

Bug report

Bug description:

import dataclasses

@dataclasses.dataclass
class NotFrozen:
    pass

@dataclasses.dataclass(frozen=True)
class Frozen:
    pass

@dataclasses.dataclass(frozen=True)
class Child(NotFrozen, Frozen):
    pass

The dataclass inheritance hierarchy is supposed to require all classes to be either frozen or non frozen, this works properly for checking that an unfrozen class does not inherit from any frozen classes, but it allows frozen classes to inherit from unfrozen ones as long as there's at least one frozen class in the MI

CPython versions tested on:

3.10

Operating systems tested on:

Windows

Linked PRs

@Batman-q96 Batman-q96 added the type-bug An unexpected behavior, bug, or error label Sep 14, 2023
@ericvsmith ericvsmith self-assigned this Sep 14, 2023
@ericvsmith
Copy link
Member

Are you saying Child is not frozen but you think it should be? Or the other way around? Can you show some example code that shows the problem? Like create a Child and show it is either frozen or not. Thanks.

@Batman-q96
Copy link
Author

Batman-q96 commented Sep 14, 2023

import dataclasses

@dataclasses.dataclass
class NotFrozen:
    pass

@dataclasses.dataclass(frozen=True)
class Frozen:
    pass

# this class fails to create with
# TypeError: cannot inherit non-frozen dataclass from a frozen one
@dataclasses.dataclass
class NotFrozenChild(NotFrozen, Frozen):
    pass

# this class has no issue with creation
@dataclasses.dataclass(frozen=True)
class FrozenChild(NotFrozen, Frozen):
    pass

The expected behavior would be that FrozenChild should fail to create with a TypeError: cannot inherit frozen dataclass from a non-frozen one. Instead FrozenChild creates with no issues (though linters such as pylance do catch this issue).

sobolevn added a commit to sobolevn/cpython that referenced this issue Sep 15, 2023
@sobolevn
Copy link
Member

Yes, I also belive that this is a bug, here's how users can face it:

def mutate_not_frozen(instance: NotFrozen) -> None:
    x.some_field = 1

mutate_not_frozen(NotFrozen())  # ok
mutate_not_frozen(FrozenChild())  # type-checkers will allow it, but will fail in runtime

Interesting, it should fail here:

        # Raise an exception if we're frozen, but none of our bases are.
        if not any_frozen_base and frozen:
            raise TypeError('cannot inherit frozen dataclass from a '
                            'non-frozen one')

and it fails correctly with just a single parent, but multiple parents should be checked with all, not any.

@ericvsmith ericvsmith added type-feature A feature request or enhancement and removed type-bug An unexpected behavior, bug, or error labels Sep 15, 2023
@ericvsmith
Copy link
Member

Since this is a change in behavior, I'm inclined to call it a feature request and not backport it.

ericvsmith pushed a commit that referenced this issue Oct 12, 2023
…ass mixins (gh-109437)

Fix inheritance of frozen dataclass from non-frozen dataclass mixins
@ericvsmith
Copy link
Member

Thanks, @sobolevn !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

3 participants