Control: tags -1 + patch

The attached patch was applied in Ubuntu.
From: Anshul Singh <anshul.si...@canonical.com>
Date: Wed, 11 Dec 2024 14:05:50 +0530
Subject: Patch to stop generating nan values in tests to work with latest attrs

Origin: upstream, https://github.com/python-attrs/cattrs/commit/96ed9a1c972814c379f9ea8faa3413aacd4ce6cb, https://github.com/python-attrs/cattrs/commit/31eff823a7114f24b0c010af314b61e01cf099a9
Author: Tin Tvrtković Tinche
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-cattrs/+bug/2089134
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1086614
---
 tests/test_baseconverter.py |  23 ++++----
 tests/test_converter.py     |  38 ++++++++------
 tests/test_gen_dict.py      |  10 ++--
 tests/typed.py              | 125 +++++++++++++++++++++++++++++++-------------
 tests/untyped.py            |   2 +-
 5 files changed, 132 insertions(+), 66 deletions(-)

diff --git a/tests/test_baseconverter.py b/tests/test_baseconverter.py
index 6305701..17b891d 100644
--- a/tests/test_baseconverter.py
+++ b/tests/test_baseconverter.py
@@ -14,7 +14,7 @@ from .typed import nested_typed_classes, simple_typed_attrs, simple_typed_classe
 unstructure_strats = one_of(just(s) for s in UnstructureStrategy)
 
 
-@given(simple_typed_classes(newtypes=False), unstructure_strats)
+@given(simple_typed_classes(newtypes=False, allow_nan=False), unstructure_strats)
 def test_simple_roundtrip(cls_and_vals, strat):
     """
     Simple classes with metadata can be unstructured and restructured.
@@ -26,7 +26,10 @@ def test_simple_roundtrip(cls_and_vals, strat):
     assert inst == converter.structure(converter.unstructure(inst), cl)
 
 
-@given(simple_typed_attrs(defaults=True, newtypes=False), unstructure_strats)
+@given(
+    simple_typed_attrs(defaults=True, newtypes=False, allow_nan=False),
+    unstructure_strats,
+)
 def test_simple_roundtrip_defaults(attr_and_strat, strat):
     """
     Simple classes with metadata can be unstructured and restructured.
@@ -42,7 +45,7 @@ def test_simple_roundtrip_defaults(attr_and_strat, strat):
     assert inst == converter.structure(converter.unstructure(inst), cl)
 
 
-@given(nested_typed_classes(newtypes=False))
+@given(nested_typed_classes(newtypes=False, allow_nan=False))
 def test_nested_roundtrip(cls_and_vals):
     """
     Nested classes with metadata can be unstructured and restructured.
@@ -54,7 +57,7 @@ def test_nested_roundtrip(cls_and_vals):
     assert inst == converter.structure(converter.unstructure(inst), cl)
 
 
-@given(nested_typed_classes(kw_only=False, newtypes=False))
+@given(nested_typed_classes(kw_only=False, newtypes=False, allow_nan=False))
 def test_nested_roundtrip_tuple(cls_and_vals):
     """
     Nested classes with metadata can be unstructured and restructured.
@@ -69,8 +72,8 @@ def test_nested_roundtrip_tuple(cls_and_vals):
 
 @settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow])
 @given(
-    simple_typed_classes(defaults=False, newtypes=False),
-    simple_typed_classes(defaults=False, newtypes=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
     unstructure_strats,
 )
 def test_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
@@ -112,8 +115,8 @@ def test_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
 @pytest.mark.skipif(not is_py310_plus, reason="3.10+ union syntax")
 @settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow])
 @given(
-    simple_typed_classes(defaults=False, newtypes=False),
-    simple_typed_classes(defaults=False, newtypes=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
     unstructure_strats,
 )
 def test_310_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
@@ -152,7 +155,7 @@ def test_310_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
         assert inst == converter.structure(converter.unstructure(inst), C)
 
 
-@given(simple_typed_classes(defaults=False, newtypes=False))
+@given(simple_typed_classes(defaults=False, newtypes=False, allow_nan=False))
 def test_optional_field_roundtrip(cl_and_vals):
     """
     Classes with optional fields can be unstructured and structured.
@@ -174,7 +177,7 @@ def test_optional_field_roundtrip(cl_and_vals):
 
 
 @pytest.mark.skipif(not is_py310_plus, reason="3.10+ union syntax")
-@given(simple_typed_classes(defaults=False, newtypes=False))
+@given(simple_typed_classes(defaults=False, newtypes=False, allow_nan=False))
 def test_310_optional_field_roundtrip(cl_and_vals):
     """
     Classes with optional fields can be unstructured and structured.
diff --git a/tests/test_converter.py b/tests/test_converter.py
index 6e0563b..3178bcd 100644
--- a/tests/test_converter.py
+++ b/tests/test_converter.py
@@ -37,7 +37,10 @@ from .typed import (
 unstructure_strats = one_of(just(s) for s in UnstructureStrategy)
 
 
-@given(simple_typed_classes() | simple_typed_dataclasses(), booleans())
+@given(
+    simple_typed_classes(allow_nan=False) | simple_typed_dataclasses(allow_nan=False),
+    booleans(),
+)
 def test_simple_roundtrip(cls_and_vals, detailed_validation):
     """
     Simple classes with metadata can be unstructured and restructured.
@@ -51,8 +54,8 @@ def test_simple_roundtrip(cls_and_vals, detailed_validation):
 
 
 @given(
-    simple_typed_classes(kw_only=False, newtypes=False)
-    | simple_typed_dataclasses(newtypes=False),
+    simple_typed_classes(kw_only=False, newtypes=False, allow_nan=False)
+    | simple_typed_dataclasses(newtypes=False, allow_nan=False),
     booleans(),
 )
 def test_simple_roundtrip_tuple(cls_and_vals, dv: bool):
@@ -69,7 +72,7 @@ def test_simple_roundtrip_tuple(cls_and_vals, dv: bool):
     assert inst == converter.structure(unstructured, cl)
 
 
-@given(simple_typed_attrs(defaults=True))
+@given(simple_typed_attrs(defaults=True, allow_nan=False))
 def test_simple_roundtrip_defaults(attr_and_vals):
     """
     Simple classes with metadata can be unstructured and restructured.
@@ -84,7 +87,9 @@ def test_simple_roundtrip_defaults(attr_and_vals):
     assert inst == converter.structure(converter.unstructure(inst), cl)
 
 
-@given(simple_typed_attrs(defaults=True, kw_only=False, newtypes=False))
+@given(
+    simple_typed_attrs(defaults=True, kw_only=False, newtypes=False, allow_nan=False)
+)
 def test_simple_roundtrip_defaults_tuple(attr_and_vals):
     """
     Simple classes with metadata can be unstructured and restructured.
@@ -100,7 +105,8 @@ def test_simple_roundtrip_defaults_tuple(attr_and_vals):
 
 
 @given(
-    simple_typed_classes(newtypes=False) | simple_typed_dataclasses(newtypes=False),
+    simple_typed_classes(newtypes=False, allow_nan=False)
+    | simple_typed_dataclasses(newtypes=False, allow_nan=False),
     unstructure_strats,
 )
 def test_simple_roundtrip_with_extra_keys_forbidden(cls_and_vals, strat):
@@ -199,7 +205,7 @@ def test_forbid_extra_keys_nested_override():
     assert cve.value.exceptions[0].extra_fields == {"b"}
 
 
-@given(nested_typed_classes(defaults=True, min_attrs=1), booleans())
+@given(nested_typed_classes(defaults=True, min_attrs=1, allow_nan=False), booleans())
 def test_nested_roundtrip(cls_and_vals, omit_if_default):
     """
     Nested classes with metadata can be unstructured and restructured.
@@ -213,7 +219,9 @@ def test_nested_roundtrip(cls_and_vals, omit_if_default):
 
 
 @given(
-    nested_typed_classes(defaults=True, min_attrs=1, kw_only=False, newtypes=False),
+    nested_typed_classes(
+        defaults=True, min_attrs=1, kw_only=False, newtypes=False, allow_nan=False
+    ),
     booleans(),
 )
 def test_nested_roundtrip_tuple(cls_and_vals, omit_if_default: bool):
@@ -232,8 +240,8 @@ def test_nested_roundtrip_tuple(cls_and_vals, omit_if_default: bool):
 
 @settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow])
 @given(
-    simple_typed_classes(defaults=False, newtypes=False),
-    simple_typed_classes(defaults=False, newtypes=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
     unstructure_strats,
 )
 def test_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
@@ -277,8 +285,8 @@ def test_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
 @pytest.mark.skipif(not is_py310_plus, reason="3.10+ union syntax")
 @settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow])
 @given(
-    simple_typed_classes(defaults=False, newtypes=False),
-    simple_typed_classes(defaults=False, newtypes=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
+    simple_typed_classes(defaults=False, newtypes=False, allow_nan=False),
     unstructure_strats,
 )
 def test_310_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
@@ -319,7 +327,7 @@ def test_310_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat):
         assert inst == converter.structure(unstructured, C)
 
 
-@given(simple_typed_classes(defaults=False))
+@given(simple_typed_classes(defaults=False, allow_nan=False))
 def test_optional_field_roundtrip(cl_and_vals):
     """
     Classes with optional fields can be unstructured and structured.
@@ -341,7 +349,7 @@ def test_optional_field_roundtrip(cl_and_vals):
 
 
 @pytest.mark.skipif(not is_py310_plus, reason="3.10+ union syntax")
-@given(simple_typed_classes(defaults=False))
+@given(simple_typed_classes(defaults=False, allow_nan=False))
 def test_310_optional_field_roundtrip(cl_and_vals):
     """
     Classes with optional fields can be unstructured and structured.
@@ -362,7 +370,7 @@ def test_310_optional_field_roundtrip(cl_and_vals):
     assert inst == converter.structure(unstructured, C)
 
 
-@given(simple_typed_classes(defaults=True))
+@given(simple_typed_classes(defaults=True, allow_nan=False))
 def test_omit_default_roundtrip(cl_and_vals):
     """
     Omit default on the converter works.
diff --git a/tests/test_gen_dict.py b/tests/test_gen_dict.py
index 0a4e851..446c789 100644
--- a/tests/test_gen_dict.py
+++ b/tests/test_gen_dict.py
@@ -163,9 +163,9 @@ def test_individual_overrides(converter_cls, cl_and_vals):
 
 
 @given(
-    cl_and_vals=nested_typed_classes()
-    | simple_typed_classes()
-    | simple_typed_dataclasses(),
+    cl_and_vals=nested_typed_classes(allow_nan=False)
+    | simple_typed_classes(allow_nan=False)
+    | simple_typed_dataclasses(allow_nan=False),
     dv=...,
 )
 def test_unmodified_generated_structuring(cl_and_vals, dv: bool):
@@ -187,7 +187,9 @@ def test_unmodified_generated_structuring(cl_and_vals, dv: bool):
 
 
 @given(
-    simple_typed_classes(min_attrs=1) | simple_typed_dataclasses(min_attrs=1), data()
+    simple_typed_classes(min_attrs=1, allow_nan=False)
+    | simple_typed_dataclasses(min_attrs=1, allow_nan=False),
+    data(),
 )
 def test_renaming(cl_and_vals, data):
     converter = Converter()
diff --git a/tests/typed.py b/tests/typed.py
index 6bed20d..2cd4db2 100644
--- a/tests/typed.py
+++ b/tests/typed.py
@@ -1,4 +1,5 @@
 """Strategies for attributes with types and classes using them."""
+
 import sys
 from collections import OrderedDict
 from collections.abc import MutableSequence as AbcMutableSequence
@@ -33,6 +34,7 @@ from hypothesis.strategies import (
     DrawFn,
     SearchStrategy,
     booleans,
+    characters,
     composite,
     dictionaries,
     fixed_dictionaries,
@@ -58,7 +60,14 @@ T = TypeVar("T")
 
 
 def simple_typed_classes(
-    defaults=None, min_attrs=0, frozen=False, kw_only=None, newtypes=True
+    defaults=None,
+    min_attrs=0,
+    frozen=False,
+    kw_only=None,
+    newtypes=True,
+    text_codec: str = "utf8",
+    allow_infinity=None,
+    allow_nan=True,
 ) -> SearchStrategy[Tuple[Type, PosArgs, KwArgs]]:
     """Yield tuples of (class, values)."""
     return lists_of_typed_attrs(
@@ -67,10 +76,15 @@ def simple_typed_classes(
         for_frozen=frozen,
         kw_only=kw_only,
         newtypes=newtypes,
+        text_codec=text_codec,
+        allow_infinity=allow_infinity,
+        allow_nan=allow_nan,
     ).flatmap(partial(_create_hyp_class, frozen=frozen))
 
 
-def simple_typed_dataclasses(defaults=None, min_attrs=0, frozen=False, newtypes=True):
+def simple_typed_dataclasses(
+    defaults=None, min_attrs=0, frozen=False, newtypes=True, allow_nan=True
+):
     """Yield tuples of (class, values)."""
     return lists_of_typed_attrs(
         defaults,
@@ -78,15 +92,20 @@ def simple_typed_dataclasses(defaults=None, min_attrs=0, frozen=False, newtypes=
         for_frozen=frozen,
         allow_mutable_defaults=False,
         newtypes=newtypes,
+        allow_nan=allow_nan,
     ).flatmap(partial(_create_dataclass, frozen=frozen))
 
 
 def simple_typed_classes_and_strats(
-    defaults=None, min_attrs=0, kw_only=None, newtypes=True
+    defaults=None, min_attrs=0, kw_only=None, newtypes=True, allow_nan=True
 ) -> SearchStrategy[Tuple[Type, SearchStrategy[PosArgs], SearchStrategy[KwArgs]]]:
     """Yield tuples of (class, (strategies))."""
     return lists_of_typed_attrs(
-        defaults, min_size=min_attrs, kw_only=kw_only, newtypes=newtypes
+        defaults,
+        min_size=min_attrs,
+        kw_only=kw_only,
+        newtypes=newtypes,
+        allow_nan=allow_nan,
     ).flatmap(_create_hyp_class_and_strat)
 
 
@@ -97,6 +116,9 @@ def lists_of_typed_attrs(
     allow_mutable_defaults=True,
     kw_only=None,
     newtypes=True,
+    text_codec="utf8",
+    allow_infinity=None,
+    allow_nan=True,
 ) -> SearchStrategy[List[Tuple[_CountingAttr, SearchStrategy[PosArg]]]]:
     # Python functions support up to 255 arguments.
     return lists(
@@ -106,6 +128,9 @@ def lists_of_typed_attrs(
             allow_mutable_defaults=allow_mutable_defaults,
             kw_only=kw_only,
             newtypes=newtypes,
+            text_codec=text_codec,
+            allow_infinity=allow_infinity,
+            allow_nan=allow_nan,
         ),
         min_size=min_size,
         max_size=50,
@@ -122,13 +147,16 @@ def simple_typed_attrs(
     allow_mutable_defaults=True,
     kw_only=None,
     newtypes=True,
+    text_codec="utf8",
+    allow_infinity=None,
+    allow_nan=True,
 ) -> SearchStrategy[Tuple[_CountingAttr, SearchStrategy[PosArgs]]]:
     if not is_39_or_later:
         res = (
-            bare_typed_attrs(defaults, kw_only)
+            any_typed_attrs(defaults, kw_only)
             | int_typed_attrs(defaults, kw_only)
-            | str_typed_attrs(defaults, kw_only)
-            | float_typed_attrs(defaults, kw_only)
+            | str_typed_attrs(defaults, kw_only, text_codec)
+            | float_typed_attrs(defaults, kw_only, allow_infinity, allow_nan)
             | frozenset_typed_attrs(defaults, legacy_types_only=True, kw_only=kw_only)
             | homo_tuple_typed_attrs(defaults, legacy_types_only=True, kw_only=kw_only)
             | path_typed_attrs(defaults, kw_only=kw_only)
@@ -170,10 +198,10 @@ def simple_typed_attrs(
             )
     else:
         res = (
-            bare_typed_attrs(defaults, kw_only)
+            any_typed_attrs(defaults, kw_only)
             | int_typed_attrs(defaults, kw_only)
-            | str_typed_attrs(defaults, kw_only)
-            | float_typed_attrs(defaults, kw_only)
+            | str_typed_attrs(defaults, kw_only, text_codec)
+            | float_typed_attrs(defaults, kw_only, allow_infinity, allow_nan)
             | frozenset_typed_attrs(defaults, kw_only=kw_only)
             | homo_tuple_typed_attrs(defaults, kw_only=kw_only)
             | path_typed_attrs(defaults, kw_only=kw_only)
@@ -274,12 +302,18 @@ def _create_dataclass(
             make_dataclass(
                 "HypDataclass",
                 [
-                    (n, a.type)
-                    if a._default is NOTHING
-                    else (
-                        (n, a.type, dc_field(default=a._default))
-                        if not isinstance(a._default, Factory)
-                        else (n, a.type, dc_field(default_factory=a._default.factory))
+                    (
+                        (n, a.type)
+                        if a._default is NOTHING
+                        else (
+                            (n, a.type, dc_field(default=a._default))
+                            if not isinstance(a._default, Factory)
+                            else (
+                                n,
+                                a.type,
+                                dc_field(default_factory=a._default.factory),
+                            )
+                        )
                     )
                     for n, a in zip(gen_attr_names(), attrs)
                 ],
@@ -316,11 +350,10 @@ def _create_hyp_class_and_strat(
 
 
 @composite
-def bare_typed_attrs(draw, defaults=None, kw_only=None):
-    """
-    Generate a tuple of an attribute and a strategy that yields values
-    appropriate for that attribute.
-    """
+def any_typed_attrs(
+    draw: DrawFn, defaults=None, kw_only=None
+) -> Tuple[_CountingAttr, SearchStrategy[None]]:
+    """Attributes typed as `Any`, having values of `None`."""
     default = NOTHING
     if defaults is True or (defaults is None and draw(booleans())):
         default = None
@@ -354,7 +387,7 @@ def int_typed_attrs(draw, defaults=None, kw_only=None):
 
 
 @composite
-def str_typed_attrs(draw, defaults=None, kw_only=None):
+def str_typed_attrs(draw, defaults=None, kw_only=None, codec: str = "utf8"):
     """
     Generate a tuple of an attribute and a strategy that yields strs for that
     attribute.
@@ -368,26 +401,28 @@ def str_typed_attrs(draw, defaults=None, kw_only=None):
             default=default,
             kw_only=draw(booleans()) if kw_only is None else kw_only,
         ),
-        text(),
+        text(characters(codec=codec)),
     )
 
 
 @composite
-def float_typed_attrs(draw, defaults=None, kw_only=None):
+def float_typed_attrs(
+    draw, defaults=None, kw_only=None, allow_infinity=None, allow_nan=True
+):
     """
     Generate a tuple of an attribute and a strategy that yields floats for that
     attribute.
     """
     default = NOTHING
     if defaults is True or (defaults is None and draw(booleans())):
-        default = draw(floats())
+        default = draw(floats(allow_infinity=allow_infinity, allow_nan=allow_nan))
     return (
         field(
             type=float,
             default=default,
             kw_only=draw(booleans()) if kw_only is None else kw_only,
         ),
-        floats(),
+        floats(allow_infinity=allow_infinity, allow_nan=allow_nan),
     )
 
 
@@ -638,9 +673,11 @@ def mutable_seq_typed_attrs(
 
     return (
         field(
-            type=AbcMutableSequence[float]
-            if not legacy_types_only
-            else MutableSequence[float],
+            type=(
+                AbcMutableSequence[float]
+                if not legacy_types_only
+                else MutableSequence[float]
+            ),
             default=default,
             kw_only=draw(booleans()) if kw_only is None else kw_only,
         ),
@@ -802,7 +839,7 @@ def dict_of_class(
 
 
 def _create_hyp_nested_strategy(
-    simple_class_strategy: SearchStrategy, kw_only=None, newtypes=True
+    simple_class_strategy: SearchStrategy, kw_only=None, newtypes=True, allow_nan=True
 ) -> SearchStrategy[Tuple[Type, SearchStrategy[PosArgs], SearchStrategy[KwArgs]]]:
     """
     Create a recursive attrs class.
@@ -817,7 +854,8 @@ def _create_hyp_nested_strategy(
     attrs_and_classes: SearchStrategy[
         Tuple[List[Tuple[_CountingAttr, PosArgs]], Tuple[Type, SearchStrategy[PosArgs]]]
     ] = tuples(
-        lists_of_typed_attrs(kw_only=kw_only, newtypes=newtypes), simple_class_strategy
+        lists_of_typed_attrs(kw_only=kw_only, newtypes=newtypes, allow_nan=allow_nan),
+        simple_class_strategy,
     )
 
     return nested_classes(attrs_and_classes)
@@ -861,22 +899,37 @@ def nested_classes(
 
 
 def nested_typed_classes_and_strat(
-    defaults=None, min_attrs=0, kw_only=None, newtypes=True
+    defaults=None, min_attrs=0, kw_only=None, newtypes=True, allow_nan=True
 ) -> SearchStrategy[Tuple[Type, SearchStrategy[PosArgs]]]:
     return recursive(
         simple_typed_classes_and_strats(
-            defaults=defaults, min_attrs=min_attrs, kw_only=kw_only, newtypes=newtypes
+            defaults=defaults,
+            min_attrs=min_attrs,
+            kw_only=kw_only,
+            newtypes=newtypes,
+            allow_nan=allow_nan,
+        ),
+        partial(
+            _create_hyp_nested_strategy,
+            kw_only=kw_only,
+            newtypes=newtypes,
+            allow_nan=allow_nan,
         ),
-        partial(_create_hyp_nested_strategy, kw_only=kw_only, newtypes=newtypes),
         max_leaves=20,
     )
 
 
 @composite
-def nested_typed_classes(draw, defaults=None, min_attrs=0, kw_only=None, newtypes=True):
+def nested_typed_classes(
+    draw, defaults=None, min_attrs=0, kw_only=None, newtypes=True, allow_nan=True
+):
     cl, strat, kwarg_strat = draw(
         nested_typed_classes_and_strat(
-            defaults=defaults, min_attrs=min_attrs, kw_only=kw_only, newtypes=newtypes
+            defaults=defaults,
+            min_attrs=min_attrs,
+            kw_only=kw_only,
+            newtypes=newtypes,
+            allow_nan=allow_nan,
         )
     )
     return cl, draw(strat), draw(kwarg_strat)
diff --git a/tests/untyped.py b/tests/untyped.py
index e155397..c2b0519 100644
--- a/tests/untyped.py
+++ b/tests/untyped.py
@@ -351,7 +351,7 @@ def float_attrs(draw, defaults=None, kw_only=None):
     """
     default = NOTHING
     if defaults is True or (defaults is None and draw(st.booleans())):
-        default = draw(st.floats())
+        default = draw(st.floats(allow_nan=False))
     return (
         attr.ib(
             default=default, kw_only=draw(st.booleans()) if kw_only is None else kw_only

Reply via email to