@@ -92,24 +92,51 @@ def _parse_commands(commands: dict[str, Any] | None, project_dir: Path) -> Itera
9292 yield Command (name , env , args , cwd , accepts_extra_args = accepts_extra_args )
9393
9494
95- def _parse_aliases (aliases : dict [str , Any ] | None ) -> Iterator [tuple [str , tuple [str , ...]]]:
96- if aliases :
97- for alias , commands in aliases .items ():
98- yield alias , tuple (_assert_list_str (commands , path = f"[tool.dev-cmd.aliases.{ alias } ]" ))
95+ def _parse_aliases (
96+ aliases : dict [str , Any ] | None ,
97+ ) -> Iterator [tuple [str , tuple [str | tuple [str , ...], ...]]]:
98+ if not aliases :
99+ return
100+
101+ def iter_commands (alias : str , obj : Any ) -> Iterator [str | tuple [str , ...]]:
102+ if not isinstance (commands , list ):
103+ raise InvalidModelError (
104+ f"Expected value at [tool.dev-cmd.aliases] `{ alias } ` to be a list containing "
105+ f"strings or lists of strings, but given: { obj } of type { type (obj )} ."
106+ )
107+
108+ for index , item in enumerate (obj ):
109+ if isinstance (item , str ):
110+ yield item
111+ elif isinstance (item , list ):
112+ if not all (isinstance (element , str ) for element in item ):
113+ raise InvalidModelError (
114+ f"Expected value at [tool.dev-cmd.aliases] `{ alias } `[{ index } ] to be a list "
115+ f"of strings, but given list with at least one non-string item: { item } ."
116+ )
117+ yield tuple (item )
118+ else :
119+ raise InvalidModelError (
120+ f"Expected value at [tool.dev-cmd.aliases] `{ alias } `[{ index } ] to be a string "
121+ f"or a list of strings, but given: { item } of type { type (item )} ."
122+ )
123+
124+ for alias , commands in aliases .items ():
125+ yield alias , tuple (iter_commands (alias , commands ))
99126
100127
101128def _parse_default (
102129 default : dict [str , Any ] | None ,
103130 commands : Mapping [str , Command ],
104- aliases : Mapping [str , tuple [Command , ...]],
105- ) -> tuple [str , tuple [Command , ...]] | None :
131+ aliases : Mapping [str , tuple [Command | tuple [ Command , ...] , ...]],
132+ ) -> tuple [str , tuple [Command | tuple [ Command , ...] , ...]] | None :
106133 if not default :
107134 if len (commands ) == 1 :
108135 name , command = next (iter (commands .items ()))
109136 return name , tuple ([command ])
110137 return None
111138
112- default_commands : tuple [str , tuple [Command , ...]] | None = None
139+ default_commands : tuple [str , tuple [Command | tuple [ Command , ...] , ...]] | None = None
113140 alias = default .pop ("alias" , None )
114141 if alias :
115142 if not isinstance (alias , str ):
@@ -162,23 +189,41 @@ def pop_dict(key: str, *, path: str) -> dict[str, Any] | None:
162189 project_dir = pyproject_toml .path .parent ,
163190 )
164191 }
165- aliases : dict [str , tuple [Command , ...]] = {}
166- for alias , cmds in _parse_aliases (pop_dict ("aliases" , path = "[tool.dev-cmd.aliases- ]" )):
192+ aliases : dict [str , tuple [Command | tuple [ Command , ...] , ...]] = {}
193+ for alias , cmds in _parse_aliases (pop_dict ("aliases" , path = "[tool.dev-cmd.aliases]" )):
167194 if alias in commands :
168195 raise InvalidModelError (
169196 f"The alias name { alias !r} conflicts with a command of the same name."
170197 )
171- alias_cmds : list [Command ] = []
172- for cmd in cmds :
173- if cmd in commands :
174- alias_cmds .append (commands [cmd ])
175- elif cmd in aliases :
176- alias_cmds .extend (aliases [cmd ])
198+ alias_cmds : list [Command | tuple [Command , ...]] = []
199+ for index , cmd in enumerate (cmds ):
200+ if isinstance (cmd , str ):
201+ if cmd in commands :
202+ alias_cmds .append (commands [cmd ])
203+ elif cmd in aliases :
204+ alias_cmds .extend (aliases [cmd ])
205+ else :
206+ raise InvalidModelError (
207+ f"The task { cmd !r} defined in alias { alias !r} is neither a command nor a "
208+ f"previously defined alias."
209+ )
177210 else :
178- raise InvalidModelError (
179- f"The task { cmd !r} defined in alias { alias !r} is neither a command nor a "
180- f"previously defined alias."
181- )
211+ parallel_cmds : list [Command ] = []
212+ for parallel_cmd in cmd :
213+ if parallel_cmd in commands :
214+ parallel_cmds .append (commands [parallel_cmd ])
215+ elif parallel_cmd in aliases :
216+ raise InvalidModelError (
217+ f"Expected value at [tool.dev-cmd.aliases] `{ alias } `[{ index } ] to be a "
218+ f"list of command names, but { parallel_cmd !r} is an alias."
219+ )
220+ else :
221+ raise InvalidModelError (
222+ f"Expected value at [tool.dev-cmd.aliases] `{ alias } `[{ index } ] to be a "
223+ f"list of command names, but { parallel_cmd !r} is doesn't correspond "
224+ f"with any defined command."
225+ )
226+ alias_cmds .append (tuple (parallel_cmds ))
182227 aliases [alias ] = tuple (alias_cmds )
183228
184229 default = _parse_default (pop_dict ("default" , path = "[tool.dev-cmd.default]" ), commands , aliases )
0 commit comments