@@ -8,9 +8,14 @@ class AstConstructible:
88 """Mixin that enables reconstruction of a class instance from an AST Call node.
99
1010 Any class whose ``__init__`` takes only scalar (``ast.Constant``) arguments
11- can inherit from this mixin to gain automatic ``from_ast_call`` support in
12- the pipeline AST parser — no changes to the parser needed when new parameters
13- are added to the class.
11+ can inherit from this mixin and get ``from_ast_call`` for free. Adding or
12+ renaming ``__init__`` parameters does *not* require touching the parser.
13+
14+ To make the AST parser recognise a new subclass by name, add one entry to
15+ ``_AST_CALLABLE_TYPES`` in ``runtime.py`` (and ensure the subclass module is
16+ imported there). Auto-registration via ``__init_subclass__`` would not remove
17+ that requirement — the registry entry only exists after the module is imported,
18+ so an explicit import would still be needed.
1419 """
1520
1621 @classmethod
@@ -21,10 +26,19 @@ def from_ast_call(cls, node: ast.Call) -> "AstConstructible":
2126 ``inspect.signature``, then merges keyword args, and calls ``cls``.
2227 """
2328 param_names = list (inspect .signature (cls ).parameters .keys ())
24- kwargs = {
25- param_names [i ]: arg .value
26- for i , arg in enumerate (node .args )
27- if isinstance (arg , ast .Constant ) and i < len (param_names )
28- }
29- kwargs |= {kw .arg : kw .value .value for kw in node .keywords if isinstance (kw .value , ast .Constant )}
29+ kwargs = {}
30+ for i , arg in enumerate (node .args ):
31+ if i >= len (param_names ):
32+ break
33+ if not isinstance (arg , ast .Constant ):
34+ raise ValueError (
35+ f"{ cls .__name__ } () positional argument { i + 1 } must be a literal value, not a dynamic expression."
36+ )
37+ kwargs [param_names [i ]] = arg .value
38+ for kw in node .keywords :
39+ if not isinstance (kw .value , ast .Constant ):
40+ raise ValueError (
41+ f"{ cls .__name__ } () keyword argument '{ kw .arg } ' must be a literal value, not a dynamic expression."
42+ )
43+ kwargs [kw .arg ] = kw .value .value
3044 return cls (** kwargs )
0 commit comments