@@ -2448,6 +2448,46 @@ class EvolveCase:
24482448 dunder__ = 5 ,
24492449 ) == EvolveCase (1 , 4 , 5 )
24502450
2451+ @pytest .mark .parametrize ("alias" , ["x=1" , "class" , "not valid" , 1 ])
2452+ def test_invalid_alias (self , alias ):
2453+ """
2454+ Invalid aliases are rejected before they can be used in generated
2455+ __init__ source code.
2456+ """
2457+
2458+ with pytest .raises (
2459+ TypeError , match = "Invalid initialization alias"
2460+ ):
2461+ @attrs .define
2462+ class C :
2463+ x : int = attrs .field (alias = alias )
2464+
2465+ def test_invalid_alias_not_executed (self , monkeypatch ):
2466+ """
2467+ Aliases are parameter names, not Python source code.
2468+ """
2469+
2470+ marker = "_attrs_alias_executed"
2471+ monkeypatch .delattr ("builtins." + marker , raising = False )
2472+
2473+ with pytest .raises (
2474+ TypeError , match = "Invalid initialization alias"
2475+ ):
2476+ attr .make_class (
2477+ "C" ,
2478+ {
2479+ "x" : attr .ib (
2480+ alias = (
2481+ "x=__import__('builtins').setattr("
2482+ "__import__('builtins'), "
2483+ f"{ marker !r} , True)"
2484+ )
2485+ )
2486+ },
2487+ )
2488+
2489+ assert getattr (__import__ ("builtins" ), marker , False ) is False
2490+
24512491 def test_alias_is_default (self ):
24522492 """
24532493 alias_is_default is True for auto-generated aliases and False for
@@ -3211,4 +3251,4 @@ def test_make_class(self):
32113251 assert () == C1 .__match_args__
32123252
32133253 C1 = make_class ("C1" , {"a" : attr .ib (kw_only = True ), "b" : attr .ib ()})
3214- assert ("b" ,) == C1 .__match_args__
3254+ assert ("b" ,) == C1 .__match_args__
0 commit comments