Skip to content

Commit 2ce47a2

Browse files
Make type.__new__() raise clear errors instead of returning None (#2851)
Signed-off-by: Emmanuel Ferdman <[email protected]>
1 parent 019e2b2 commit 2ce47a2

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ What's New in astroid 4.0.1?
1313
============================
1414
Release date: TBA
1515

16+
* Make `type.__new__()` raise clear errors instead of returning `None`
1617

1718

1819
What's New in astroid 4.0.0?

astroid/bases.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -571,10 +571,14 @@ def _infer_type_new_call(
571571
raise InferenceError(context=context) from e
572572
if not isinstance(mcs, nodes.ClassDef):
573573
# Not a valid first argument.
574-
return None
574+
raise InferenceError(
575+
"type.__new__() requires a class for metaclass", context=context
576+
)
575577
if not mcs.is_subtype_of("builtins.type"):
576578
# Not a valid metaclass.
577-
return None
579+
raise InferenceError(
580+
"type.__new__() metaclass must be a subclass of type", context=context
581+
)
578582

579583
# Verify the name
580584
try:
@@ -583,10 +587,14 @@ def _infer_type_new_call(
583587
raise InferenceError(context=context) from e
584588
if not isinstance(name, nodes.Const):
585589
# Not a valid name, needs to be a const.
586-
return None
590+
raise InferenceError(
591+
"type.__new__() requires a constant for name", context=context
592+
)
587593
if not isinstance(name.value, str):
588594
# Needs to be a string.
589-
return None
595+
raise InferenceError(
596+
"type.__new__() requires a string for name", context=context
597+
)
590598

591599
# Verify the bases
592600
try:
@@ -595,14 +603,18 @@ def _infer_type_new_call(
595603
raise InferenceError(context=context) from e
596604
if not isinstance(bases, nodes.Tuple):
597605
# Needs to be a tuple.
598-
return None
606+
raise InferenceError(
607+
"type.__new__() requires a tuple for bases", context=context
608+
)
599609
try:
600610
inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts]
601611
except StopIteration as e:
602612
raise InferenceError(context=context) from e
603613
if any(not isinstance(base, nodes.ClassDef) for base in inferred_bases):
604614
# All the bases needs to be Classes
605-
return None
615+
raise InferenceError(
616+
"type.__new__() requires classes for bases", context=context
617+
)
606618

607619
# Verify the attributes.
608620
try:
@@ -611,7 +623,9 @@ def _infer_type_new_call(
611623
raise InferenceError(context=context) from e
612624
if not isinstance(attrs, nodes.Dict):
613625
# Needs to be a dictionary.
614-
return None
626+
raise InferenceError(
627+
"type.__new__() requires a dict for attrs", context=context
628+
)
615629
cls_locals: dict[str, list[InferenceResult]] = collections.defaultdict(list)
616630
for key, value in attrs.items:
617631
try:
@@ -664,9 +678,13 @@ def infer_call_result(
664678
and self.bound.name == "type"
665679
and self.name == "__new__"
666680
and isinstance(caller, nodes.Call)
667-
and len(caller.args) == 4
668681
):
669682
# Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call.
683+
if len(caller.args) != 4:
684+
raise InferenceError(
685+
f"type.__new__() requires 4 arguments, got {len(caller.args)}",
686+
context=context,
687+
)
670688
new_cls = self._infer_type_new_call(caller, context)
671689
if new_cls:
672690
return iter((new_cls,))

0 commit comments

Comments
 (0)