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.0b2: 4 tests failuires #547

Open
befeleme opened this issue Jun 11, 2024 · 5 comments
Open

Python 3.13.0b2: 4 tests failuires #547

befeleme opened this issue Jun 11, 2024 · 5 comments
Milestone

Comments

@befeleme
Copy link

  • cattrs version: 23.2.3
  • Python version: 3.13.0b2
  • Operating System: Fedora Linux 41

Description

I'm trying to build cattrs as RPM for Fedora Linux 41 with Python 3.13.0b2.
4 tests fail with two types of failures. See traceback below.

What I Did

_________________ test_collection_unstructure_override_mapping _________________
[gw9] linux -- Python 3.13.0 /usr/bin/python3
    @pytest.mark.skipif(not is_py39_plus, reason="Requires Python 3.9+")
    def test_collection_unstructure_override_mapping():
        """Test overriding unstructuring mappings."""
    
        # Using Counter
        c = Converter(unstruct_collection_overrides={Counter: Map})
        assert c.unstructure(Counter({1: 2})) == Map({1: 2})
>       assert c.unstructure(Counter({1: 2}), unstructure_as=Counter[int]) == Map({1: 2})
E       assert Counter({1: 2}) == immutables.Map({1: 2})
E         Use -v to get more diff
c          = <cattrs.converters.Converter object at 0xffff8413d620>
tests/test_unstructure_collections.py:168: AssertionError
________________________________ test_renaming _________________________________
[gw5] linux -- Python 3.13.0 /usr/bin/python3
    @given(
>       simple_typed_classes(min_attrs=1) | simple_typed_dataclasses(min_attrs=1), data()
    )
f          = <function given.<locals>.run_test_as_given.<locals>.wrapped_test at 0xffff7c5dbba0>
tests/test_gen_dict.py:190: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
cl_and_vals = (<class 'tests.typed.HypDataclass'>, (nan,), {}), data = data(...)
    @given(
        simple_typed_classes(min_attrs=1) | simple_typed_dataclasses(min_attrs=1), data()
    )
    def test_renaming(cl_and_vals, data):
        converter = Converter()
        cl, vals, kwargs = cl_and_vals
        attrs = fields(cl)
    
        to_replace = data.draw(sampled_from(attrs))
    
        u_fn = make_dict_unstructure_fn(
            cl, converter, **{to_replace.name: override(rename="class")}
        )
        s_fn = make_dict_structure_fn(
            cl, converter, **{to_replace.name: override(rename="class")}
        )
    
        converter.register_structure_hook(cl, s_fn)
        converter.register_unstructure_hook(cl, u_fn)
    
        inst = cl(*vals, **kwargs)
    
        raw = converter.unstructure(inst)
    
        assert "class" in raw
    
        new_inst = converter.structure(raw, cl)
    
>       assert inst == new_inst
E       AssertionError: assert HypDataclass(a=nan) == HypDataclass(a=nan)
E         
E         Differing attributes:
E         ['a']
E         
E         Drill down into differing attribute a:
E           a: nan != nan
E       Falsifying example: test_renaming(
E           cl_and_vals=(tests.typed.HypDataclass, (nan,), {}),  # Saw 1 signaling NaN
E           data=data(...),
E       )
E       Draw 1: Field(name='a',type=<class 'float'>,default=<dataclasses._MISSING_TYPE object at 0xffff7f1c2660>,default_factory=<dataclasses._MISSING_TYPE object at 0xffff7f1c2660>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)
E       Explanation:
E           These lines were always and only run by failing examples:
E               /usr/lib/python3.13/site-packages/_pytest/assertion/util.py:456
attrs      = (Field(name='a',type=<class 'float'>,default=<dataclasses._MISSING_TYPE object at 0xffff7f1c2660>,default_factory=<dat...xffff7f1c2660>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD),)
cl         = <class 'tests.typed.HypDataclass'>
cl_and_vals = (<class 'tests.typed.HypDataclass'>, (nan,), {})
converter  = <cattrs.converters.Converter object at 0xffff72bc2de0>
data       = data(...)
inst       = HypDataclass(a=nan)
kwargs     = {}
new_inst   = HypDataclass(a=nan)
raw        = {'class': nan}
s_fn       = <function structure_HypDataclass at 0xffff72bd7b00>
to_replace = Field(name='a',type=<class 'float'>,default=<dataclasses._MISSING_TYPE object at 0xffff7f1c2660>,default_factory=<data... 0xffff7f1c2660>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD)
u_fn       = <function unstructure_HypDataclass at 0xffff77496f20>
vals       = (nan,)
tests/test_gen_dict.py:217: AssertionError
_________________________ test_simple_roundtrip_tuple __________________________
[gw6] linux -- Python 3.13.0 /usr/bin/python3
    @given(
>       simple_typed_classes(kw_only=False, newtypes=False)
        | simple_typed_dataclasses(newtypes=False),
        booleans(),
    )
f          = <function given.<locals>.run_test_as_given.<locals>.wrapped_test at 0xffff7c35a980>
tests/test_converter.py:54: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
cls_and_vals = (<class 'tests.typed.HypDataclass'>, (nan,), {}), dv = False
    @given(
        simple_typed_classes(kw_only=False, newtypes=False)
        | simple_typed_dataclasses(newtypes=False),
        booleans(),
    )
    def test_simple_roundtrip_tuple(cls_and_vals, dv: bool):
        """
        Simple classes with metadata can be unstructured and restructured.
        """
        converter = Converter(
            unstruct_strat=UnstructureStrategy.AS_TUPLE, detailed_validation=dv
        )
        cl, vals, _ = cls_and_vals
        inst = cl(*vals)
        unstructured = converter.unstructure(inst)
        assert "Hyp" not in repr(unstructured)
>       assert inst == converter.structure(unstructured, cl)
E       AssertionError: assert HypDataclass(a=nan) == HypDataclass(a=nan)
E         
E         Differing attributes:
E         ['a']
E         
E         Drill down into differing attribute a:
E           a: nan != nan
E       Falsifying example: test_simple_roundtrip_tuple(
E           cls_and_vals=(tests.typed.HypDataclass, (nan,), {}),  # Saw 1 signaling NaN
E           dv=False,  # or any other generated value
E       )
E       Explanation:
E           These lines were always and only run by failing examples:
E               /usr/lib/python3.13/site-packages/_pytest/assertion/util.py:456
_          = {}
cl         = <class 'tests.typed.HypDataclass'>
cls_and_vals = (<class 'tests.typed.HypDataclass'>, (nan,), {})
converter  = <cattrs.converters.Converter object at 0xffff725bc4a0>
dv         = False
inst       = HypDataclass(a=nan)
unstructured = (nan,)
vals       = (nan,)
tests/test_converter.py:69: AssertionError
_______________ test_simple_roundtrip_with_extra_keys_forbidden ________________
[gw6] linux -- Python 3.13.0 /usr/bin/python3
    @given(
>       simple_typed_classes(newtypes=False) | simple_typed_dataclasses(newtypes=False),
        unstructure_strats,
    )
f          = <function given.<locals>.run_test_as_given.<locals>.wrapped_test at 0xffff7c35b920>
tests/test_converter.py:103: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
cls_and_vals = (<class 'tests.typed.HypDataclass'>, (nan,), {})
strat = <UnstructureStrategy.AS_DICT: 'asdict'>
    @given(
        simple_typed_classes(newtypes=False) | simple_typed_dataclasses(newtypes=False),
        unstructure_strats,
    )
    def test_simple_roundtrip_with_extra_keys_forbidden(cls_and_vals, strat):
        """
        Simple classes can be unstructured and restructured with forbid_extra_keys=True.
        """
        converter = Converter(unstruct_strat=strat, forbid_extra_keys=True)
        cl, vals, kwargs = cls_and_vals
        assume(strat is UnstructureStrategy.AS_DICT or not kwargs)
        inst = cl(*vals, **kwargs)
        unstructured = converter.unstructure(inst)
        assert "Hyp" not in repr(unstructured)
>       assert inst == converter.structure(unstructured, cl)
E       AssertionError: assert HypDataclass(a=nan) == HypDataclass(a=nan)
E         
E         Differing attributes:
E         ['a']
E         
E         Drill down into differing attribute a:
E           a: nan != nan
E       Falsifying example: test_simple_roundtrip_with_extra_keys_forbidden(
E           cls_and_vals=(tests.typed.HypDataclass, (nan,), {}),  # Saw 1 signaling NaN
E           strat=UnstructureStrategy.AS_DICT,  # or any other generated value
E       )
E       Explanation:
E           These lines were always and only run by failing examples:
E               /usr/lib/python3.13/site-packages/_pytest/assertion/util.py:456
E               /usr/lib/python3.13/site-packages/_pytest/assertion/util.py:468
E               /usr/lib64/python3.13/reprlib.py:23
cl         = <class 'tests.typed.HypDataclass'>
cls_and_vals = (<class 'tests.typed.HypDataclass'>, (nan,), {})
converter  = <cattrs.converters.Converter object at 0xffff63042ca0>
inst       = HypDataclass(a=nan)
kwargs     = {}
strat      = <UnstructureStrategy.AS_DICT: 'asdict'>
unstructured = {'a': nan}
vals       = (nan,)
tests/test_converter.py:116: AssertionError
=========================== short test summary info ============================
FAILED tests/test_unstructure_collections.py::test_collection_unstructure_override_mapping
FAILED tests/test_gen_dict.py::test_renaming - AssertionError: assert HypData...
FAILED tests/test_converter.py::test_simple_roundtrip_tuple - AssertionError:...
FAILED tests/test_converter.py::test_simple_roundtrip_with_extra_keys_forbidden
= 4 failed, 576 passed, 1 skipped, 15 xfailed, 24 warnings in 215.73s (0:03:35) =
@Tinche
Copy link
Member

Tinche commented Jun 11, 2024

Unfortunately 3.13 testing for the main branch is currently blocked by some of our dependencies, so I'm waiting on that to proceed.

I don't plan to test 23.2.3 on 3.12, it'll be 24.1.0.

Here's the PR: #543

@Tinche Tinche added this to the 24.1 milestone Jun 11, 2024
@hroncok
Copy link

hroncok commented Jun 17, 2024

3/4 of the failures are likely caused by this difference between Python 3.12 and 3.13:

>>> from dataclasses import dataclass
>>> @dataclass
... class a:
...     a: float
...     
>>> nan = float('nan')
>>> nan == nan  # on both
False
>>> a(nan) == a(nan)  # on 3.12
True
>>> a(nan) == a(nan)  # on 3.13
False

I believe this might be related to python/cpython#104904

@hroncok
Copy link

hroncok commented Jun 17, 2024

I've reported python/cpython#120645

@Tinche
Copy link
Member

Tinche commented Jun 17, 2024

The new behavior looks more correct to me.

Interestingly, on 3.12:

(nan,) == (nan,)

Very surprised by this.

@Tinche
Copy link
Member

Tinche commented Jun 20, 2024

I think I fixed the nan issues on the tin/3.13 branch.

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

3 participants