From 523fb9e889c2a5dfe8ab2f15df7d45ed623da22d Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Tue, 7 Oct 2025 23:04:24 +0300 Subject: [PATCH 1/2] Make `type.__new__()` raise clear errors instead of returning `None` Signed-off-by: Emmanuel Ferdman --- astroid/bases.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/astroid/bases.py b/astroid/bases.py index a029da6d4..625da31aa 100644 --- a/astroid/bases.py +++ b/astroid/bases.py @@ -571,10 +571,14 @@ def _infer_type_new_call( raise InferenceError(context=context) from e if not isinstance(mcs, nodes.ClassDef): # Not a valid first argument. - return None + raise InferenceError( + "type.__new__() requires a class for metaclass", context=context + ) if not mcs.is_subtype_of("builtins.type"): # Not a valid metaclass. - return None + raise InferenceError( + "type.__new__() metaclass must be a subclass of type", context=context + ) # Verify the name try: @@ -583,10 +587,14 @@ def _infer_type_new_call( raise InferenceError(context=context) from e if not isinstance(name, nodes.Const): # Not a valid name, needs to be a const. - return None + raise InferenceError( + "type.__new__() requires a constant for name", context=context + ) if not isinstance(name.value, str): # Needs to be a string. - return None + raise InferenceError( + "type.__new__() requires a string for name", context=context + ) # Verify the bases try: @@ -595,14 +603,18 @@ def _infer_type_new_call( raise InferenceError(context=context) from e if not isinstance(bases, nodes.Tuple): # Needs to be a tuple. - return None + raise InferenceError( + "type.__new__() requires a tuple for bases", context=context + ) try: inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts] except StopIteration as e: raise InferenceError(context=context) from e if any(not isinstance(base, nodes.ClassDef) for base in inferred_bases): # All the bases needs to be Classes - return None + raise InferenceError( + "type.__new__() requires classes for bases", context=context + ) # Verify the attributes. try: @@ -611,7 +623,9 @@ def _infer_type_new_call( raise InferenceError(context=context) from e if not isinstance(attrs, nodes.Dict): # Needs to be a dictionary. - return None + raise InferenceError( + "type.__new__() requires a dict for attrs", context=context + ) cls_locals: dict[str, list[InferenceResult]] = collections.defaultdict(list) for key, value in attrs.items: try: @@ -664,9 +678,13 @@ def infer_call_result( and self.bound.name == "type" and self.name == "__new__" and isinstance(caller, nodes.Call) - and len(caller.args) == 4 ): # Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call. + if len(caller.args) != 4: + raise InferenceError( + f"type.__new__() requires 4 arguments, got {len(caller.args)}", + context=context, + ) new_cls = self._infer_type_new_call(caller, context) if new_cls: return iter((new_cls,)) From 1688ef96a37e68a198f13dc79185d010aa0fcc77 Mon Sep 17 00:00:00 2001 From: Emmanuel Ferdman Date: Wed, 8 Oct 2025 00:16:31 +0300 Subject: [PATCH 2/2] Make `type.__new__()` raise clear errors instead of returning `None` Signed-off-by: Emmanuel Ferdman --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 3e4af6e9b..85fca7462 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,7 @@ What's New in astroid 4.0.1? ============================ Release date: TBA +* Make `type.__new__()` raise clear errors instead of returning `None` What's New in astroid 4.0.0?