77
88from lm_eval .api .group import ConfigurableGroup , GroupConfig
99from lm_eval .api .task import ConfigurableTask
10- from lm_eval .tasks ._config_loader import load_yaml as load_cfg
10+ from lm_eval .tasks ._config_loader import load_yaml
1111from lm_eval .tasks .index import Entry , Kind
1212
1313
14- load_cfg_cached = load_cfg # type: ignore[no-redef]
15-
16-
1714class TaskFactory :
1815 """
1916 Turns a *Entry* (plus optional overrides) into a
20- *Task* (from task_v3) | *ConfigurableTask* | *GroupConfig* hierarchy.
21-
22- For YAML tasks, uses the task_v3.Task builder pattern to automatically
23- select the appropriate Task subclass based on output_type.
17+ *Task* | *ConfigurableTask* | *GroupConfig* hierarchy.
2418 """
2519
2620 def __init__ (self , * , meta : dict [str , Any ] | None = None ):
@@ -35,9 +29,9 @@ def build(
3529 registry : Mapping [str , Entry ],
3630 ):
3731 """
38- • entry.kind == TASK / PY_TASK ➜ returns instantiated task object
39- • entry.kind == GROUP ➜ returns (GroupConfig, mapping-of-subtasks)
40- • entry.kind == TAG ➜ returns mapping-of-tasks (tag expansion)
32+ * entry.kind == TASK / PY_TASK -> returns instantiated task object
33+ * entry.kind == GROUP -> returns (GroupConfig, mapping-of-subtasks)
34+ * entry.kind == TAG -> returns mapping-of-tasks (tag expansion)
4135 """
4236 if entry .kind is Kind .TAG :
4337 return self ._build_tag (entry , overrides , registry )
@@ -47,20 +41,22 @@ def build(
4741
4842 return self ._build_task (entry , overrides )
4943
50- def _build_task (self , entry : Entry , overrides : dict [str , Any ] | None ) -> dict :
44+ def _build_task (self , entry : Entry , overrides : dict [str , Any ] | None ):
5145 """Build a task and return it wrapped in a dict {task_name: task_obj}."""
5246 cfg = self ._load_full_config (entry , overrides )
47+ # Use cfg["task"] as key (may be overridden, e.g., for namespacing)
48+ task_name = cfg ["task" ]
5349
5450 if "class" in cfg : # PY_TASK route
5551 cls = cfg ["class" ]
5652 obj = cls (config = cfg ) if _ctor_accepts_config (cls ) else cls ()
5753 if hasattr (obj , "config" ) and hasattr (obj .config , "task" ):
58- obj .config .task = entry . name
59- return {entry . name : obj }
54+ obj .config .task = task_name
55+ return {task_name : obj }
6056
6157 # Regular YAML task - use ConfigurableTask
6258 task_obj = ConfigurableTask (config = cfg )
63- return {entry . name : task_obj }
59+ return {task_name : task_obj }
6460
6561 def _build_group (
6662 self ,
@@ -71,46 +67,58 @@ def _build_group(
7167 raw_cfg = self ._load_full_config (entry , None )
7268 grp_cfg = {k : v for k , v in raw_cfg .items () if k in GroupConfig .__annotations__ }
7369 grp_cfg ["metadata" ] = grp_cfg .get ("metadata" , {}) | self ._meta
74- # Use ConfigurableGroup (hashable) instead of GroupConfig (dict, unhashable)
7570 group_obj = ConfigurableGroup (config = grp_cfg )
7671 group_name = entry .name
7772
7873 children : dict [str , Any ] = {}
7974 for item in group_obj .config ["task" ]:
75+ # Step 1: Normalize - extract base_name and item_overrides
8076 if isinstance (item , str ):
81- # Case 1: String reference - look up in registry
8277 base_name = item
83- child = self .build (
84- registry [item ],
85- overrides = overrides , # group-level overrides propagate
86- registry = registry ,
87- )
78+ item_overrides = overrides or {}
8879 elif isinstance (item , dict ):
8980 base_name = item ["task" ]
90- if base_name in registry :
91- # Case 2: Modify existing indexed task
92- child = self .build (
93- registry [base_name ],
94- overrides = item , # per-item override
95- registry = registry ,
96- )
97- else :
98- # Case 3: Create new task inline (not indexed)
99- task_cfg = {** item }
100- task_cfg ["metadata" ] = task_cfg .get ("metadata" , {}) | self ._meta
101- task_obj = ConfigurableTask (config = task_cfg )
102- child = {base_name : task_obj }
81+ item_overrides = item
10382 else :
10483 raise TypeError (
10584 f"Unsupported sub-entry { item !r} in group '{ entry .name } '"
10685 )
10786
108- # Namespace ALL child tasks with group_name::task_name
109- namespaced_child = {}
110- for task_name , task_obj in child .items ():
111- namespaced_name = f"{ group_name } ::{ task_name } "
112- namespaced_child [namespaced_name ] = task_obj
113- children .update (namespaced_child )
87+ # Step 2: Handle inline task (not in registry)
88+ if base_name not in registry :
89+ namespaced = f"{ group_name } ::{ base_name } "
90+ task_cfg = {** item_overrides , "task" : namespaced }
91+ task_cfg ["metadata" ] = task_cfg .get ("metadata" , {}) | self ._meta
92+ children [namespaced ] = ConfigurableTask (config = task_cfg )
93+ continue
94+
95+ # Step 3: Build based on entry kind
96+ child_entry = registry [base_name ]
97+
98+ if child_entry .kind is Kind .GROUP :
99+ child = self .build (
100+ child_entry , overrides = item_overrides , registry = registry
101+ )
102+ elif child_entry .kind is Kind .TAG :
103+ child = {}
104+ for task_name in child_entry .tags :
105+ namespaced = f"{ group_name } ::{ task_name } "
106+ child .update (
107+ self .build (
108+ registry [task_name ],
109+ overrides = {"task" : namespaced , ** item_overrides },
110+ registry = registry ,
111+ )
112+ )
113+ else : # TASK or PY_TASK
114+ namespaced = f"{ group_name } ::{ base_name } "
115+ child = self .build (
116+ child_entry ,
117+ overrides = {"task" : namespaced , ** item_overrides },
118+ registry = registry ,
119+ )
120+
121+ children .update (child )
114122
115123 return {group_obj : children }
116124
@@ -119,7 +127,7 @@ def _build_tag(
119127 entry : Entry ,
120128 overrides : dict [str , Any ] | None ,
121129 registry : Mapping [str , Entry ],
122- ) -> dict :
130+ ):
123131 """Build all tasks in a tag and return merged dict."""
124132 result = {}
125133 for name in entry .tags :
@@ -130,7 +138,7 @@ def _load_full_config(
130138 self , entry : Entry , overrides : dict [str , Any ] | None
131139 ) -> dict [str , Any ]:
132140 if entry .yaml_path :
133- cfg = deepcopy (load_cfg_cached (entry .yaml_path , resolve_func = True ))
141+ cfg = deepcopy (load_yaml (entry .yaml_path , resolve_func = True ))
134142 else :
135143 cfg : dict [str , Any ] = {
136144 "metadata" : {"config" : "unknown" }
0 commit comments