args.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. from typing import Dict, List
  2. import logging
  3. logger = logging.getLogger(__name__)
  4. # NOTE: This helper supports both syntaxes:
  5. # --var KEY=VALUE
  6. # --var KEY VALUE
  7. # It also tolerates passing values via ctx.args when using allow_extra_args.
  8. def parse_var_inputs(var_items: List[str], extra_args: List[str]) -> Dict[str, str]:
  9. overrides: Dict[str, str] = {}
  10. # First, parse items collected by Typer's --var Option (usually KEY=VALUE forms)
  11. for item in var_items:
  12. if item is None:
  13. continue
  14. if "=" in item:
  15. key, value = item.split("=", 1)
  16. if key:
  17. overrides[key] = value
  18. else:
  19. # If user provided just a key via --var KEY, try to find the next value in extra args
  20. key = item
  21. value = _pop_next_value(extra_args)
  22. overrides[key] = value if value is not None else ""
  23. # Next, scan extra_args for any leftover --var occurrences using space-separated form
  24. i = 0
  25. while i < len(extra_args):
  26. tok = extra_args[i]
  27. if tok in ("--var", "-v"):
  28. name = None
  29. value = None
  30. # name may be next token; it can also be name=value
  31. if i + 1 < len(extra_args):
  32. nxt = extra_args[i + 1]
  33. if "=" in nxt:
  34. name, value = nxt.split("=", 1)
  35. i += 1
  36. else:
  37. name = nxt
  38. if i + 2 < len(extra_args):
  39. valtok = extra_args[i + 2]
  40. if not valtok.startswith("-"):
  41. value = valtok
  42. i += 2
  43. else:
  44. i += 1
  45. else:
  46. i += 1
  47. if name:
  48. overrides[name] = value if value is not None else ""
  49. elif tok.startswith("--var=") or tok.startswith("-v="):
  50. remainder = tok.split("=", 1)[1]
  51. if "=" in remainder:
  52. name, value = remainder.split("=", 1)
  53. else:
  54. name, value = remainder, _pop_next_value(extra_args[i + 1:])
  55. if name:
  56. overrides[name] = value if value is not None else ""
  57. i += 1
  58. return overrides
  59. def _pop_next_value(args: List[str]) -> str | None:
  60. """Return the first non-flag token from args, if any, without modifying caller's list.
  61. This is a best-effort for --var KEY VALUE when Typer didn't bind VALUE to --var.
  62. """
  63. for tok in args:
  64. if not tok.startswith("-"):
  65. return tok
  66. return None