| 321 | |
| 322 | |
| 323 | def parse_target( |
| 324 | target: str, default: Optional[str] = None, isa_glob: bool = False |
| 325 | ) -> tuple[Optional[str], Optional[str]]: |
| 326 | from dvc.dvcfile import LOCK_FILE, PROJECT_FILE, is_valid_filename |
| 327 | from dvc.exceptions import DvcException |
| 328 | from dvc.parsing import JOIN |
| 329 | |
| 330 | if not target: |
| 331 | return None, None |
| 332 | |
| 333 | default = default or PROJECT_FILE |
| 334 | if isa_glob: |
| 335 | path, _, glob = target.rpartition(":") |
| 336 | return path or default, glob or None |
| 337 | |
| 338 | # look for first "@", so as not to assume too much about stage name |
| 339 | # eg: it might contain ":" in a generated stages from dict which might |
| 340 | # affect further parsing with the regex. |
| 341 | group, _, key = target.partition(JOIN) |
| 342 | match = TARGET_REGEX.match(group) |
| 343 | |
| 344 | if not match: |
| 345 | return target, None |
| 346 | |
| 347 | path, name = (match.group("path"), match.group("name")) |
| 348 | |
| 349 | if name and key: |
| 350 | name += f"{JOIN}{key}" |
| 351 | |
| 352 | if path: |
| 353 | if os.path.basename(path) == LOCK_FILE: |
| 354 | raise DvcException( |
| 355 | "Did you mean: `{}`?".format(target.replace(".lock", ".yaml", 1)) |
| 356 | ) |
| 357 | if not name: |
| 358 | ret = (target, None) |
| 359 | return ret if is_valid_filename(target) else ret[::-1] |
| 360 | return path or default, name |
| 361 | |
| 362 | |
| 363 | def glob_targets(targets, glob=True, recursive=True): |