66import dataclasses
77import itertools
88import os
9- from collections import defaultdict
9+ from collections import defaultdict , deque
1010from dataclasses import dataclass
1111from pathlib import Path
1212from typing import Any , Container , Dict , Iterable , Iterator , List , Mapping , Set , cast
@@ -838,7 +838,7 @@ def _gather_all_required_step_names(
838838
839839def parse_dev_config (
840840 pyproject_toml : PyProjectToml , * requested_steps : str , requested_python : Python | None = None
841- ) -> Configuration :
841+ ) -> tuple [ Configuration , tuple [ str , ...]] :
842842 pyproject_data = pyproject_toml .parse ()
843843 try :
844844 dev_cmd_data = _assert_dict_str_keys (
@@ -875,6 +875,7 @@ def pop_dict(key: str, *, path: str) -> dict[str, Any] | None:
875875 required_step_names = (
876876 _gather_all_required_step_names (requested_steps , tasks_data ) or known_names
877877 )
878+ requested_step_names : dict [str , str ] = {step : step for step in requested_steps }
878879 for required_step_name in required_step_names :
879880 if required_step_name in known_names :
880881 required_steps [required_step_name ].append (())
@@ -883,23 +884,46 @@ def pop_dict(key: str, *, path: str) -> dict[str, Any] | None:
883884 if not required_step_name .startswith (f"{ known_name } -" ):
884885 continue
885886
886- required_steps [known_name ].append (
887- tuple (
888- Factor (factor )
889- for factor in required_step_name [len (known_name ) + 1 :].split ("-" )
890- )
887+ factors = [] # type: List[Factor]
888+ factor_chars = [] # type: List[str]
889+ chars = deque (required_step_name [len (known_name ) + 1 :])
890+ while chars :
891+ while chars :
892+ char = chars .popleft ()
893+
894+ if char != "-" :
895+ factor_chars .append (char )
896+ continue
897+
898+ # Escaped - (--)
899+ if chars and chars [0 ] == "-" :
900+ factor_chars .append (char )
901+ chars .popleft ()
902+ continue
903+
904+ if not chars :
905+ factor_chars .append (char )
906+
907+ break
908+ factors .append (Factor ("" .join (factor_chars )))
909+ factor_chars .clear ()
910+
911+ required_steps [known_name ].append (tuple (factors ))
912+ requested_step_names [required_step_name ] = (
913+ f"{ known_name } -{ '-' .join (factors )} " if factors else known_name
891914 )
892915 break
893916
894- commands : dict [str , Command | DeactivatedCommand ] = {
895- cmd .name : cmd
896- for cmd in _parse_commands (
897- commands_data ,
898- required_steps ,
899- project_dir = pyproject_toml .path .parent ,
900- marker_environment = marker_environment ,
901- )
902- }
917+ commands : dict [str , Command | DeactivatedCommand ] = {}
918+ for cmd in _parse_commands (
919+ commands_data ,
920+ required_steps ,
921+ project_dir = pyproject_toml .path .parent ,
922+ marker_environment = marker_environment ,
923+ ):
924+ existing = commands .setdefault (cmd .name , cmd )
925+ if isinstance (existing , DeactivatedCommand ) and isinstance (cmd , Command ):
926+ commands [cmd .name ] = cmd
903927 if not commands :
904928 raise InvalidModelError (
905929 "No commands are defined in the [tool.dev-cmd.commands] table. At least one must be "
@@ -919,7 +943,7 @@ def pop_dict(key: str, *, path: str) -> dict[str, Any] | None:
919943 f"Unexpected configuration keys in the [tool.dev-cmd] table: { ' ' .join (dev_cmd_data )} "
920944 )
921945
922- return Configuration (
946+ configuration = Configuration (
923947 commands = tuple (cmd for cmd in commands .values () if isinstance (cmd , Command )),
924948 tasks = tuple (tasks .values ()),
925949 default = default ,
@@ -929,3 +953,5 @@ def pop_dict(key: str, *, path: str) -> dict[str, Any] | None:
929953 pythons = pythons ,
930954 source = pyproject_toml .path ,
931955 )
956+
957+ return configuration , tuple (requested_step_names [step ] for step in requested_steps )
0 commit comments