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

Python 3.13 (dev) bug: cannot inherit frozen dataclass from a non-frozen one #1969

Open
simonw opened this issue Apr 14, 2024 · 4 comments
Open

Comments

@simonw
Copy link
Contributor

simonw commented Apr 14, 2024

Running Pint against the current Python 3.13 developer preview throws this error:

pint/__init__.py:18: in <module>
    from .delegates.formatter._format_helpers import formatter
pint/delegates/__init__.py:12: in <module>
    from . import txt_defparser
pint/delegates/txt_defparser/__init__.py:12: in <module>
    from .defparser import DefParser
pint/delegates/txt_defparser/defparser.py:10: in <module>
    from . import block, common, context, defaults, group, plain, system
pint/delegates/txt_defparser/common.py:23: in <module>
    @dataclass(frozen=True)
../../../.pyenv/versions/3.13-dev/lib/python3.13/dataclasses.py:1247: in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash,
../../../.pyenv/versions/3.13-dev/lib/python3.13/dataclasses.py:1015: in _process_class
    raise TypeError('cannot inherit frozen dataclass from a '
E   TypeError: cannot inherit frozen dataclass from a non-frozen one
@simonw
Copy link
Contributor Author

simonw commented Apr 14, 2024

Steps to reproduce:

cd /tmp
git clone https://github.com/hgrecco/pint
cd pint
python3.13 -m venv venv
# Or for me that was:
# ~/.pyenv/versions/3.13-dev/bin/python -m venv venv
source venv/bin/activate
python -m pip install pytest
python -m pip install -e .
pytest

@simonw
Copy link
Contributor Author

simonw commented Apr 14, 2024

@simonw
Copy link
Contributor Author

simonw commented Apr 14, 2024

I think this is the code that the trackback complains about:

from dataclasses import dataclass, field
import flexparser as fp
from ... import errors
from ..base_defparser import ParserConfig
@dataclass(frozen=True)
class DefinitionSyntaxError(errors.DefinitionSyntaxError, fp.ParsingError):
"""A syntax error was found in a definition. Combines:

And yes, DefinitionSyntaxError() there is marked as frozen=True - but the errors.DefinitionSyntaxError class it extends is marked frozen=False here:

pint/pint/errors.py

Lines 105 to 115 in f2e4081

@dataclass(frozen=False)
class DefinitionSyntaxError(ValueError, PintError):
"""Raised when a textual definition has a syntax error."""
msg: str
def __str__(self):
return self.msg
def __reduce__(self):
return self.__class__, tuple(getattr(self, f.name) for f in fields(self))

@simonw
Copy link
Contributor Author

simonw commented Apr 14, 2024

Modifying pint/errors.py and replacing every instance of @dataclass(frozen=False) with @dataclass(frozen=True) addresses this problem, but I don't know if it's the right solution.

diff --git a/pint/errors.py b/pint/errors.py
index 59d3b45..f080f52 100644
--- a/pint/errors.py
+++ b/pint/errors.py
@@ -81,12 +81,12 @@ class WithDefErr:
         return DefinitionError(self.name, self.__class__, msg)
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class PintError(Exception):
     """Base exception for all Pint errors."""
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class DefinitionError(ValueError, PintError):
     """Raised when a definition is not properly constructed."""
 
@@ -102,7 +102,7 @@ class DefinitionError(ValueError, PintError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class DefinitionSyntaxError(ValueError, PintError):
     """Raised when a textual definition has a syntax error."""
 
@@ -115,7 +115,7 @@ class DefinitionSyntaxError(ValueError, PintError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class RedefinitionError(ValueError, PintError):
     """Raised when a unit or prefix is redefined."""
 
@@ -130,7 +130,7 @@ class RedefinitionError(ValueError, PintError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class UndefinedUnitError(AttributeError, PintError):
     """Raised when the units are not defined in the unit registry."""
 
@@ -150,13 +150,13 @@ class UndefinedUnitError(AttributeError, PintError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class PintTypeError(TypeError, PintError):
     def __reduce__(self):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class DimensionalityError(PintTypeError):
     """Raised when trying to convert between incompatible units."""
 
@@ -183,7 +183,7 @@ class DimensionalityError(PintTypeError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class OffsetUnitCalculusError(PintTypeError):
     """Raised on ambiguous operations with offset units."""
 
@@ -208,7 +208,7 @@ class OffsetUnitCalculusError(PintTypeError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class LogarithmicUnitCalculusError(PintTypeError):
     """Raised on inappropriate operations with logarithmic units."""
 
@@ -233,7 +233,7 @@ class LogarithmicUnitCalculusError(PintTypeError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class UnitStrippedWarning(UserWarning, PintError):
     msg: str
 
@@ -241,13 +241,13 @@ class UnitStrippedWarning(UserWarning, PintError):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class UnexpectedScaleInContainer(Exception):
     def __reduce__(self):
         return self.__class__, tuple(getattr(self, f.name) for f in fields(self))
 
 
-@dataclass(frozen=False)
+@dataclass(frozen=True)
 class UndefinedBehavior(UserWarning, PintError):
     msg: str

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

1 participant