Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-astroid for openSUSE:Factory 
checked in at 2026-03-24 18:48:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-astroid (Old)
 and      /work/SRC/openSUSE:Factory/.python-astroid.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-astroid"

Tue Mar 24 18:48:00 2026 rev:66 rq:1342069 version:4.1.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-astroid/python-astroid.changes    
2026-03-03 15:29:42.390014440 +0100
+++ /work/SRC/openSUSE:Factory/.python-astroid.new.8177/python-astroid.changes  
2026-03-24 18:48:17.441037478 +0100
@@ -1,0 +2,22 @@
+Mon Mar 23 15:57:35 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 4.1.2:
+  * Fix crash accessing property `fset` in generic classes with
+    type annotations.
+  * Fix infinite recursion caused by cyclic inference in
+    ``Constraint``.
+  * Fix ``RecursionError`` in ``_compute_mro()`` when circular
+    class hierarchies are created through runtime name rebinding.
+  * Fix ``DuplicateBasesError`` crash in dataclass transform when
+    a class has duplicate bases in its MRO (e.g., ``Protocol``
+    appearing both directly and indirectly). Catch ``MroError``
+    at ``.mro()`` call sites in ``brain_dataclasses.py``,
+    consistent with the existing pattern elsewhere.
+  * Catch ``MemoryError`` when inferring f-strings with extremely
+    large format widths (e.g. ``f'{0:11111111111}'``) so that
+    inference yields ``Uninferable`` instead of crashing.
+  * Fix ``ValueError`` in ``__str__``/``repr`` and error messages
+    when nodes have extreme values (very long identifiers or large
+    integers).
+
+-------------------------------------------------------------------

Old:
----
  astroid-4.1.1-gh.tar.gz

New:
----
  astroid-4.1.2-gh.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-astroid.spec ++++++
--- /var/tmp/diff_new_pack.RmBPix/_old  2026-03-24 18:48:18.285071693 +0100
+++ /var/tmp/diff_new_pack.RmBPix/_new  2026-03-24 18:48:18.285071693 +0100
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-astroid
-Version:        4.1.1
+Version:        4.1.2
 Release:        0
 Summary:        Representation of Python source as an AST for pylint
 License:        LGPL-2.1-or-later

++++++ astroid-4.1.1-gh.tar.gz -> astroid-4.1.2-gh.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/.github/workflows/ci.yaml 
new/astroid-4.1.2/.github/workflows/ci.yaml
--- old/astroid-4.1.1/.github/workflows/ci.yaml 2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/.github/workflows/ci.yaml 2026-03-22 16:06:01.000000000 
+0100
@@ -4,7 +4,7 @@
   push:
     branches:
       - main
-      - 2.*
+      - maintenance/**
   pull_request:
   workflow_dispatch:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/CONTRIBUTORS.txt 
new/astroid-4.1.2/CONTRIBUTORS.txt
--- old/astroid-4.1.1/CONTRIBUTORS.txt  2026-02-23 03:34:23.000000000 +0100
+++ new/astroid-4.1.2/CONTRIBUTORS.txt  2026-03-22 16:06:01.000000000 +0100
@@ -109,6 +109,7 @@
 - Anthony Truchet <[email protected]>
 - Anthony Sottile <[email protected]>
 - Alexander Shadchin <[email protected]>
+- Fridayworks <[email protected]>
 - wgehalo <[email protected]>
 - tejaschauhan36912 <[email protected]>
 - rr- <[email protected]>
@@ -219,6 +220,7 @@
 - Alexander Scheel <[email protected]>
 - Alexander Presnyakov <[email protected]>
 - Ahmed Azzaoui <[email protected]>
+- Casey Jones <[email protected]>
 
 Co-Author
 ---------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/ChangeLog new/astroid-4.1.2/ChangeLog
--- old/astroid-4.1.1/ChangeLog 2026-02-23 03:34:23.000000000 +0100
+++ new/astroid-4.1.2/ChangeLog 2026-03-22 16:06:01.000000000 +0100
@@ -8,11 +8,50 @@
 Release date: TBA
 
 
+What's New in astroid 4.1.3?
+============================
+Release date: TBA
+
+
 
 What's New in astroid 4.1.2?
 ============================
-Release date: TBA
+Release date: 2026-03-22
+
+* Fix crash accessing property `fset` in generic classes with type annotations.
+  Closes #2996
+
+* Fix infinite recursion caused by cyclic inference in ``Constraint``.
+
+* Fix ``RecursionError`` in ``_compute_mro()`` when circular class hierarchies
+  are created through runtime name rebinding. Circular bases are now resolved
+  to the original class instead of recursing.
+
+  Closes #2967
+  Closes pylint-dev/pylint#10821
+
+* Fix ``DuplicateBasesError`` crash in dataclass transform when a class has
+  duplicate bases in its MRO (e.g., ``Protocol`` appearing both directly and
+  indirectly). Catch ``MroError`` at ``.mro()`` call sites in
+  ``brain_dataclasses.py``, consistent with the existing pattern elsewhere.
+
+  Closes #2628
+
+* Fix ``FunctionModel`` returning descriptor attributes for builtin functions.
+
+  Closes #2743
+
+* Catch ``MemoryError`` when inferring f-strings with extremely large format
+  widths (e.g. ``f'{0:11111111111}'``) so that inference yields ``Uninferable``
+  instead of crashing.
+
+  Closes #2762
+
+* Fix ``ValueError`` in ``__str__``/``repr`` and error messages when nodes have
+  extreme values (very long identifiers or large integers). Clamp pprint width
+  to a minimum of 1 and truncate oversized values in error messages.
 
+  Closes #2764
 
 
 What's New in astroid 4.1.1?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/astroid/__pkginfo__.py 
new/astroid-4.1.2/astroid/__pkginfo__.py
--- old/astroid-4.1.1/astroid/__pkginfo__.py    2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/astroid/__pkginfo__.py    2026-03-22 16:06:01.000000000 
+0100
@@ -2,5 +2,5 @@
 # For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
 # Copyright (c) 
https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
 
-__version__ = "4.1.1"
+__version__ = "4.1.2"
 version = __version__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/astroid/bases.py 
new/astroid-4.1.2/astroid/bases.py
--- old/astroid-4.1.1/astroid/bases.py  2026-02-23 03:34:23.000000000 +0100
+++ new/astroid-4.1.2/astroid/bases.py  2026-03-22 16:06:01.000000000 +0100
@@ -183,7 +183,10 @@
                 if not constraint_stmt.parent_of(stmt):
                     stmt_constraints.update(potential_constraints)
             for inf in stmt.infer(context=context):
-                if all(constraint.satisfied_by(inf) for constraint in 
stmt_constraints):
+                if all(
+                    constraint.satisfied_by(inf, context)
+                    for constraint in stmt_constraints
+                ):
                     yield inf
                     inferred = True
                 else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/astroid/brain/brain_dataclasses.py 
new/astroid-4.1.2/astroid/brain/brain_dataclasses.py
--- old/astroid-4.1.1/astroid/brain/brain_dataclasses.py        2026-02-23 
03:34:23.000000000 +0100
+++ new/astroid-4.1.2/astroid/brain/brain_dataclasses.py        2026-03-22 
16:06:01.000000000 +0100
@@ -21,7 +21,12 @@
 from astroid.brain.helpers import is_class_var
 from astroid.builder import parse
 from astroid.const import PY313_PLUS
-from astroid.exceptions import AstroidSyntaxError, InferenceError, 
UseInferenceDefault
+from astroid.exceptions import (
+    AstroidSyntaxError,
+    InferenceError,
+    MroError,
+    UseInferenceDefault,
+)
 from astroid.inference_tip import inference_tip
 from astroid.manager import AstroidManager
 from astroid.typing import InferenceResult
@@ -174,7 +179,12 @@
     # See TODO down below
     # all_have_defaults = True
 
-    for base in reversed(node.mro()):
+    try:
+        mro = node.mro()
+    except MroError:
+        return pos_only_store, kw_only_store
+
+    for base in reversed(mro):
         if not base.is_dataclass:
             continue
         try:
@@ -224,7 +234,12 @@
 
 def _get_previous_field_default(node: nodes.ClassDef, name: str) -> 
nodes.NodeNG | None:
     """Get the default value of a previously defined field."""
-    for base in reversed(node.mro()):
+    try:
+        mro = node.mro()
+    except MroError:
+        return None
+
+    for base in reversed(mro):
         if not base.is_dataclass:
             continue
         if name in base.locals:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/astroid/constraint.py 
new/astroid-4.1.2/astroid/constraint.py
--- old/astroid-4.1.1/astroid/constraint.py     2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/astroid/constraint.py     2026-03-22 16:06:01.000000000 
+0100
@@ -12,6 +12,7 @@
 from typing import TYPE_CHECKING
 
 from astroid import helpers, nodes, util
+from astroid.context import InferenceContext
 from astroid.exceptions import AstroidTypeError, InferenceError, MroError
 from astroid.typing import InferenceResult
 
@@ -47,7 +48,9 @@
         """
 
     @abstractmethod
-    def satisfied_by(self, inferred: InferenceResult) -> bool:
+    def satisfied_by(
+        self, inferred: InferenceResult, context: InferenceContext
+    ) -> bool:
         """Return True if this constraint is satisfied by the given inferred 
value."""
 
 
@@ -76,7 +79,9 @@
 
         return None
 
-    def satisfied_by(self, inferred: InferenceResult) -> bool:
+    def satisfied_by(
+        self, inferred: InferenceResult, context: InferenceContext
+    ) -> bool:
         """Return True if this constraint is satisfied by the given inferred 
value."""
         # Assume true if uninferable
         if inferred is util.Uninferable:
@@ -112,7 +117,9 @@
 
         return None
 
-    def satisfied_by(self, inferred: InferenceResult) -> bool:
+    def satisfied_by(
+        self, inferred: InferenceResult, context: InferenceContext
+    ) -> bool:
         """Return True for uninferable results, or depending on negate flag:
 
         - negate=False: satisfied if boolean value is True
@@ -153,7 +160,9 @@
 
         return None
 
-    def satisfied_by(self, inferred: InferenceResult) -> bool:
+    def satisfied_by(
+        self, inferred: InferenceResult, context: InferenceContext
+    ) -> bool:
         """Return True for uninferable results, or depending on negate flag:
 
         - negate=False: satisfied when inferred is an instance of the checked 
types.
@@ -163,8 +172,8 @@
             return True
 
         try:
-            types = helpers.class_or_tuple_to_container(self.classinfo)
-            matches_checked_types = helpers.object_isinstance(inferred, types)
+            types = helpers.class_or_tuple_to_container(self.classinfo, 
context)
+            matches_checked_types = helpers.object_isinstance(inferred, types, 
context)
 
             if matches_checked_types is util.Uninferable:
                 return True
@@ -204,7 +213,9 @@
 
         return None
 
-    def satisfied_by(self, inferred: InferenceResult) -> bool:
+    def satisfied_by(
+        self, inferred: InferenceResult, context: InferenceContext
+    ) -> bool:
         """Return True for uninferable/ambiguous results, or depending on 
negate flag:
 
         - negate=False: satisfied when both operands are equal.
@@ -215,7 +226,7 @@
         if inferred is util.Uninferable:
             return True
 
-        operand_inferred = util.safe_infer(self.operand)
+        operand_inferred = util.safe_infer(self.operand, context)
         if operand_inferred is util.Uninferable or operand_inferred is None:
             return True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/astroid/interpreter/objectmodel.py 
new/astroid-4.1.2/astroid/interpreter/objectmodel.py
--- old/astroid-4.1.1/astroid/interpreter/objectmodel.py        2026-02-23 
03:34:23.000000000 +0100
+++ new/astroid-4.1.2/astroid/interpreter/objectmodel.py        2026-03-22 
16:06:01.000000000 +0100
@@ -87,8 +87,11 @@
         string = "%(cname)s(%(fields)s)"
         alignment = len(cname) + 1
         for field in sorted(self.attributes()):
-            width = 80 - len(field) - alignment
-            lines = pprint.pformat(field, indent=2, 
width=width).splitlines(True)
+            width = max(80 - len(field) - alignment, 1)
+            try:
+                lines = pprint.pformat(field, indent=2, 
width=width).splitlines(True)
+            except ValueError:
+                lines = [f"<{type(field).__name__}>"]
 
             inner = [lines[0]]
             for line in lines[1:]:
@@ -269,6 +272,10 @@
 
 
 class FunctionModel(ObjectModel):
+    def _is_builtin_func(self) -> bool:
+        func = self._instance
+        return isinstance(func.parent, nodes.Module) and not 
func.root().pure_python
+
     @property
     def attr___name__(self):
         return node_classes.Const(value=self._instance.name, 
parent=self._instance)
@@ -287,6 +294,8 @@
     @property
     def attr___defaults__(self):
         func = self._instance
+        if self._is_builtin_func():
+            raise AttributeInferenceError(target=func, 
attribute="__defaults__")
         if not func.args.defaults:
             return node_classes.Const(value=None, parent=func)
 
@@ -296,6 +305,10 @@
 
     @property
     def attr___annotations__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(
+                target=self._instance, attribute="__annotations__"
+            )
         obj = node_classes.Dict(
             parent=self._instance,
             lineno=self._instance.lineno,
@@ -336,6 +349,8 @@
 
     @property
     def attr___dict__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(target=self._instance, 
attribute="__dict__")
         return node_classes.Dict(
             parent=self._instance,
             lineno=self._instance.lineno,
@@ -344,10 +359,27 @@
             end_col_offset=self._instance.end_col_offset,
         )
 
-    attr___globals__ = attr___dict__
+    @property
+    def attr___globals__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(
+                target=self._instance, attribute="__globals__"
+            )
+        return node_classes.Dict(
+            parent=self._instance,
+            lineno=self._instance.lineno,
+            col_offset=self._instance.col_offset,
+            end_lineno=self._instance.end_lineno,
+            end_col_offset=self._instance.end_col_offset,
+        )
 
     @property
     def attr___kwdefaults__(self):
+        if self._is_builtin_func():
+            raise AttributeInferenceError(
+                target=self._instance, attribute="__kwdefaults__"
+            )
+
         def _default_args(args, parent):
             for arg in args.kwonlyargs:
                 try:
@@ -379,6 +411,9 @@
     def attr___get__(self):
         func = self._instance
 
+        if self._is_builtin_func():
+            raise AttributeInferenceError(target=func, attribute="__get__")
+
         class DescriptorBoundMethod(bases.BoundMethod):
             """Bound method which knows how to understand calling descriptor
             binding.
@@ -976,12 +1011,11 @@
             :param func: property for which the setter has to be found
             :return: the setter function or None
             """
-            for target in [
-                t for t in func.parent.get_children() if t.name == 
func.function.name
-            ]:
-                for dec_name in target.decoratornames():
-                    if dec_name.endswith(func.function.name + ".setter"):
-                        return target
+            for node in func.parent.body:
+                if isinstance(node, (nodes.FunctionDef, 
nodes.AsyncFunctionDef)):
+                    for dec_name in node.decoratornames():
+                        if dec_name.endswith(func.function.name + ".setter"):
+                            return node
             return None
 
         func_setter = find_setter(func)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/astroid/nodes/node_classes.py 
new/astroid-4.1.2/astroid/nodes/node_classes.py
--- old/astroid-4.1.1/astroid/nodes/node_classes.py     2026-02-23 
03:34:23.000000000 +0100
+++ new/astroid-4.1.2/astroid/nodes/node_classes.py     2026-03-22 
16:06:01.000000000 +0100
@@ -2151,7 +2151,11 @@
                 message="Type error {error!r}", node=self, index=index, 
context=context
             ) from exc
 
-        raise AstroidTypeError(f"{self!r} (value={self.value})")
+        try:
+            value_str = str(self.value)
+        except ValueError:
+            value_str = f"<{type(self.value).__name__} (too large to display)>"
+        raise AstroidTypeError(f"{self!r} (value={value_str})")
 
     def has_dynamic_getattr(self) -> bool:
         """Check if the node has a custom __getattr__ or __getattribute__.
@@ -4756,8 +4760,9 @@
                         end_col_offset=self.end_col_offset,
                     )
                     continue
-                except (ValueError, TypeError):
-                    # happens when format_spec.value is invalid
+                except (ValueError, TypeError, MemoryError):
+                    # ValueError/TypeError: invalid format spec
+                    # MemoryError: format spec with huge width (e.g. 
f'{0:11111111111}')
                     yield util.Uninferable
                     uninferable_already_generated = True
                 continue
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/astroid/nodes/node_ng.py 
new/astroid-4.1.2/astroid/nodes/node_ng.py
--- old/astroid-4.1.1/astroid/nodes/node_ng.py  2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/astroid/nodes/node_ng.py  2026-03-22 16:06:01.000000000 
+0100
@@ -198,8 +198,11 @@
         result = []
         for field in self._other_fields + self._astroid_fields:
             value = getattr(self, field, "Unknown")
-            width = 80 - len(field) - alignment
-            lines = pprint.pformat(value, indent=2, 
width=width).splitlines(True)
+            width = max(80 - len(field) - alignment, 1)
+            try:
+                lines = pprint.pformat(value, indent=2, 
width=width).splitlines(True)
+            except ValueError:
+                lines = [f"<{type(value).__name__}>"]
 
             inner = [lines[0]]
             for line in lines[1:]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/astroid-4.1.1/astroid/nodes/scoped_nodes/scoped_nodes.py 
new/astroid-4.1.2/astroid/nodes/scoped_nodes/scoped_nodes.py
--- old/astroid-4.1.1/astroid/nodes/scoped_nodes/scoped_nodes.py        
2026-02-23 03:34:23.000000000 +0100
+++ new/astroid-4.1.2/astroid/nodes/scoped_nodes/scoped_nodes.py        
2026-03-22 16:06:01.000000000 +0100
@@ -2841,11 +2841,41 @@
                 baseobj = baseobj._proxied
             if not isinstance(baseobj, ClassDef):
                 continue
+            if baseobj is self:
+                # Circular base due to name rebinding (e.g. pdb.Pdb = CustomPdb
+                # where CustomPdb inherits from pdb.Pdb). Fall back to the
+                # first non-circular inferred value from the base expression.
+                baseobj = self._resolve_circular_base(stmt, context)
+                if baseobj is None:
+                    continue
             if not baseobj.hide:
                 yield baseobj
             else:
                 yield from baseobj.bases
 
+    def _resolve_circular_base(
+        self,
+        stmt: nodes.NodeNG,
+        context: InferenceContext | None,
+    ) -> ClassDef | None:
+        """Resolve a circular base reference by finding the original class.
+
+        When a name is rebound to a subclass (e.g. ``pdb.Pdb = CustomPdb``),
+        ``_infer_last`` follows the rebinding and returns the subclass itself.
+        This method iterates through all inferred values to find the first
+        non-circular ClassDef.
+        """
+        inf_context = copy_context(context)
+        try:
+            for inferred in stmt.infer(context=inf_context):
+                if isinstance(inferred, bases.Instance):
+                    inferred = inferred._proxied
+                if isinstance(inferred, ClassDef) and inferred is not self:
+                    return inferred
+        except InferenceError:
+            pass
+        return None
+
     def _compute_mro(self, context: InferenceContext | None = None):
         if self.qname() == "builtins.object":
             return [self]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/requirements_minimal.txt 
new/astroid-4.1.2/requirements_minimal.txt
--- old/astroid-4.1.1/requirements_minimal.txt  2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/requirements_minimal.txt  2026-03-22 16:06:01.000000000 
+0100
@@ -1,5 +1,5 @@
 # Tools used when releasing
-contributors-txt>=0.7.4
+contributors-txt>=1.0.1
 tbump~=6.11
 
 # Tools used to run tests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/script/.contributors_aliases.json 
new/astroid-4.1.2/script/.contributors_aliases.json
--- old/astroid-4.1.1/script/.contributors_aliases.json 2026-02-23 
03:34:23.000000000 +0100
+++ new/astroid-4.1.2/script/.contributors_aliases.json 2026-03-22 
16:06:01.000000000 +0100
@@ -37,6 +37,10 @@
     "mails": ["[email protected]", 
"[email protected]"],
     "name": "James Addison"
   },
+  "[email protected]": {
+    "mails": ["[email protected]"],
+    "name": "Casey Jones"
+  },
   "[email protected]": {
     "mails": ["[email protected]", "[email protected]"],
     "name": "Hashem Nasarat"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/tbump.toml new/astroid-4.1.2/tbump.toml
--- old/astroid-4.1.1/tbump.toml        2026-02-23 03:34:23.000000000 +0100
+++ new/astroid-4.1.2/tbump.toml        2026-03-22 16:06:01.000000000 +0100
@@ -1,7 +1,7 @@
 github_url = "https://github.com/pylint-dev/astroid";
 
 [version]
-current = "4.1.1"
+current = "4.1.2"
 regex = '''
 ^(?P<major>0|[1-9]\d*)
 \.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/tests/brain/test_dataclasses.py 
new/astroid-4.1.2/tests/brain/test_dataclasses.py
--- old/astroid-4.1.1/tests/brain/test_dataclasses.py   2026-02-23 
03:34:23.000000000 +0100
+++ new/astroid-4.1.2/tests/brain/test_dataclasses.py   2026-03-22 
16:06:01.000000000 +0100
@@ -1237,3 +1237,73 @@
     fourth_init: bases.UnboundMethod = next(fourth.infer())
     assert [a.name for a in fourth_init.args.args] == ["self", "other_attr", 
"attr"]
     assert [a.name for a in fourth_init.args.defaults] == ["Uninferable"]
+
+
+def test_dataclass_with_duplicate_bases_no_crash():
+    """Regression test for https://github.com/pylint-dev/astroid/issues/2628.
+
+    A dataclass inheriting from a class with duplicate bases in MRO
+    (e.g., Protocol appearing both directly and indirectly) should not
+    crash with DuplicateBasesError during AST transformation.
+    """
+    code = """
+    import dataclasses
+    from typing import TypeVar, Protocol
+
+    BaseT = TypeVar("BaseT")
+    T = TypeVar("T", bound=BaseT)
+
+    class ConfigBase(Protocol[BaseT]):
+        ...
+
+    class Config(ConfigBase[T], Protocol[T]):
+        ...
+
+    @dataclasses.dataclass
+    class DatasetConfig(Config[T]):
+        name: str = "default"
+
+    DatasetConfig.__init__  #@
+    """
+    node = astroid.extract_node(code)
+    # Should not raise DuplicateBasesError — graceful degradation instead
+    inferred = next(node.infer())
+    assert inferred is not None
+
+
+def test_dataclass_with_duplicate_bases_field_default():
+    """Regression test for _get_previous_field_default with broken MRO.
+
+    When a parent dataclass defines a field with a default and a child (with
+    duplicate bases in its MRO) re-annotates that field without a value,
+    _get_previous_field_default should not crash with DuplicateBasesError.
+
+    See https://github.com/pylint-dev/astroid/issues/2628.
+    """
+    code = """
+    import dataclasses
+    from typing import TypeVar, Protocol
+
+    BaseT = TypeVar("BaseT")
+    T = TypeVar("T", bound=BaseT)
+
+    class ConfigBase(Protocol[BaseT]):
+        ...
+
+    class Config(ConfigBase[T], Protocol[T]):
+        ...
+
+    @dataclasses.dataclass
+    class BaseConfig(Config[T]):
+        name: str = "default"
+
+    @dataclasses.dataclass
+    class ChildConfig(BaseConfig[T]):
+        name: str
+
+    ChildConfig.__init__  #@
+    """
+    node = astroid.extract_node(code)
+    # Should not raise DuplicateBasesError in _get_previous_field_default
+    inferred = next(node.infer())
+    assert inferred is not None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/tests/test_inference.py 
new/astroid-4.1.2/tests/test_inference.py
--- old/astroid-4.1.1/tests/test_inference.py   2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/tests/test_inference.py   2026-03-22 16:06:01.000000000 
+0100
@@ -5262,6 +5262,28 @@
         assert value_node.value == result
 
 
+def test_fstring_large_width_no_memory_error() -> None:
+    """MemoryError should not crash inference for f-strings with huge width.
+
+    Regression test for https://github.com/pylint-dev/astroid/issues/2762
+    """
+
+    class OOMInt(int):
+        """An int whose __format__ raises MemoryError, simulating 
f'{0:>11111111111}'."""
+
+        def __format__(self, spec: str) -> str:
+            raise MemoryError
+
+    node = extract_node("f'{0:>9}'")
+    # Replace the Const value with our OOMInt so format() raises MemoryError
+    # without actually allocating a huge string.
+    fmt_value = node.values[0]
+    fmt_value.value.value = OOMInt(0)
+    inferred = node.inferred()
+    assert len(inferred) == 1
+    assert inferred[0] is util.Uninferable
+
+
 def test_augassign_recursion() -> None:
     """Make sure inference doesn't throw a RecursionError.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/tests/test_nodes.py 
new/astroid-4.1.2/tests/test_nodes.py
--- old/astroid-4.1.1/tests/test_nodes.py       2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/tests/test_nodes.py       2026-03-22 16:06:01.000000000 
+0100
@@ -41,6 +41,7 @@
 from astroid.exceptions import (
     AstroidBuildingError,
     AstroidSyntaxError,
+    AstroidTypeError,
     AttributeInferenceError,
     StatementMissing,
 )
@@ -2253,3 +2254,42 @@
     # This should not raise a DeprecationWarning
     # pylint: disable-next=unused-import
     from astroid import builtin_lookup
+
+
+def test_str_long_name_no_crash() -> None:
+    """str() should not crash with ValueError on nodes with long names.
+
+    Regression test for https://github.com/pylint-dev/astroid/issues/2764
+    """
+    long_name = "a" * 200
+    code = f"class {long_name}:\n    pass"
+    module = parse(code)
+    # This should not raise ValueError('width must be != 0')
+    result = str(module.body[0])
+    assert long_name in result
+
+
+def test_str_large_int_no_crash() -> None:
+    """str() should not crash with ValueError on nodes with large integer 
values.
+
+    Regression test for https://github.com/pylint-dev/astroid/issues/2785
+    """
+    code = "x = 10 ** 5000"
+    module = parse(code)
+    # Infer the BinOp to get a Const with a huge int value
+    inferred = next(module.body[0].value.infer())
+    assert isinstance(inferred.value, int)
+    # This should not raise ValueError about integer string conversion limit
+    result = str(inferred)
+    assert "int" in result
+
+
+def test_str_large_int_getitem_no_crash() -> None:
+    """getitem error message should not crash with large integer values."""
+    code = "x = 10 ** 5000"
+    module = parse(code)
+    inferred = next(module.body[0].value.infer())
+    assert isinstance(inferred.value, int)
+    # Trigger the error path that formats the value
+    with pytest.raises(AstroidTypeError, match=r"too large to display|int"):
+        inferred.getitem(nodes.Const(0))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/tests/test_object_model.py 
new/astroid-4.1.2/tests/test_object_model.py
--- old/astroid-4.1.1/tests/test_object_model.py        2026-02-23 
03:34:23.000000000 +0100
+++ new/astroid-4.1.2/tests/test_object_model.py        2026-03-22 
16:06:01.000000000 +0100
@@ -998,3 +998,49 @@
     thisclass_inferred = next(thisclass_node.infer())
     assert isinstance(thisclass_inferred, nodes.ClassDef)
     assert thisclass_inferred.name == "Base"
+
+
[email protected](
+    "attr",
+    [
+        "__get__",
+        "__defaults__",
+        "__annotations__",
+        "__dict__",
+        "__globals__",
+        "__kwdefaults__",
+    ],
+)
+def test_builtin_func_no_descriptor_attrs(attr: str) -> None:
+    """Test builtin functions lack descriptor protocol attributes."""
+    node = builder.extract_node(f"eval.{attr}")
+    with pytest.raises(InferenceError):
+        next(node.infer())
+
+
+def test_getattr_on_property_fset_with_annassign_does_not_crash() -> None:
+    """Test that getattr on property fset doesn't crash with AnnAssign."""
+    node = builder.extract_node("""
+    from typing import TypeVar, Generic
+
+    T = TypeVar('T')
+
+    class Base:
+        _x: object
+        @property
+        def x(self):
+            return self._x
+        @x.setter
+        def x(self, val):
+            self._x = val
+
+    class Child(Base, Generic[T]):
+        _x: T
+        @property
+        def x(self) -> T:
+            return self._x
+        @x.setter
+        def x(self, val):
+            getattr(Base.x, "fset", None)  #@
+    """)
+    next(node.infer())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/tests/test_regrtest.py 
new/astroid-4.1.2/tests/test_regrtest.py
--- old/astroid-4.1.1/tests/test_regrtest.py    2026-02-23 03:34:23.000000000 
+0100
+++ new/astroid-4.1.2/tests/test_regrtest.py    2026-03-22 16:06:01.000000000 
+0100
@@ -486,9 +486,8 @@
     assert node.name == "c"
 
 
[email protected](reason="Not fixed yet")
 def test_regression_eval_get_of_arg() -> None:
-    """Regression test for #2743"""
+    """Regression test for #2743."""
     node = _extract_single_node("eval.__get__(1)")
     with pytest.raises(InferenceError):
         next(node.infer())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/astroid-4.1.1/tests/test_scoped_nodes.py 
new/astroid-4.1.2/tests/test_scoped_nodes.py
--- old/astroid-4.1.1/tests/test_scoped_nodes.py        2026-02-23 
03:34:23.000000000 +0100
+++ new/astroid-4.1.2/tests/test_scoped_nodes.py        2026-03-22 
16:06:01.000000000 +0100
@@ -1696,6 +1696,29 @@
         self.assertIsInstance(cm.exception, MroError)
         self.assertIsInstance(cm.exception, ResolveError)
 
+    def test_mro_circular_name_rebinding(self) -> None:
+        """MRO computation should handle circular name rebinding.
+
+        When a module-level name is rebound to a subclass of itself,
+        _infer_last follows the rebinding and returns the subclass.
+        The MRO computation should resolve the cycle by falling back
+        to the original class.
+
+        Regression test for https://github.com/pylint-dev/astroid/issues/2967
+        """
+        astroid = builder.parse("""
+        import pdb
+
+        class CustomPdb(pdb.Pdb):
+            pass
+
+        pdb.Pdb = CustomPdb
+        """)
+        self.assertEqualMro(
+            astroid["CustomPdb"],
+            ["CustomPdb", "Pdb", "Bdb", "Cmd", "object"],
+        )
+
     def test_mro_with_factories(self) -> None:
         cls = builder.extract_node("""
         def MixinFactory(cls):

Reply via email to