shivaam commented on issue #60142:
URL: https://github.com/apache/airflow/issues/60142#issuecomment-4204186516

   Thanks for the feedback @bugraoz93!
   
   I looked into supporting both positional and `--flag` styles for required 
params. Unfortunately argparse doesn't natively support this — a parameter is 
either positional (`dag_id`) or a flag (`--dag-id`), never both.
   
   **Why it's not straightforward:**
   
   The closest workaround is registering all params as `--flags`, adding a 
`nargs='*'` catch-all for bare values, and using `parse_intermixed_args` to map 
positionals into unfilled flag slots after parsing. But this means we lose 
argparse's built-in validation, type checking, help formatting, and 
`required=True` for those params — we'd essentially reimplement positional 
argument handling ourselves on top of argparse.
   
   **Options:**
   
   1. **Keep it positional for required params** (current PR) — the simplest, 
most conventional choice. Required params are positional, optional params are 
flags. All argparse features work, clean help output.
   
   2. **Two-pass parsing** — maintain two parsers per command: one with 
required params as positional, one with them as `--flags required=True`. Try 
positional first, fall back to flags. Users can use either style, just not 
mixed in the same invocation:
      ```bash
      # both work:
      airflowctl xcom add my_dag my_task my_key
      airflowctl xcom add --dag-id=my_dag --task-id=my_task --key=my_key
      
      # but not mixed:
      airflowctl xcom add my_dag --task-id=my_task my_key  # would fail
      ```
      No argparse hacks needed (both parsers are standard), but doubles the 
parser setup and mixed usage isn't supported.
   
   3. **Cap positional count** — first 1-2 required params (like `dag_id`) are 
positional, rest stay as `--flag required=True`. Common CLI pattern (like `git 
checkout <branch> --force`). No hacks, all argparse features work.
   
   I'd recommend Option 1 for simplicity. Happy to go with whichever you prefer!
   
   ---
   
   <details>
   <summary>Details on the <code>parse_intermixed_args</code> workaround (and 
why I didn't recommend it)</summary>
   
   The idea is to register all required params as `--flags` only (no argparse 
positionals), add a single `nargs='*'` argument to collect any bare values, 
then map those bare values into whichever flag slots the user didn't fill:
   
   ```python
   PARAM_ORDER = ['dag_id', 'task_id', 'key']
   
   parser.add_argument('--dag-id', dest='dag_id', default=None)
   parser.add_argument('--task-id', dest='task_id', default=None)
   parser.add_argument('--key', default=None)
   parser.add_argument('positionals', nargs='*')
   
   args = parser.parse_intermixed_args(argv)
   
   # map bare values into unfilled flag slots, left to right
   unfilled = [d for d in PARAM_ORDER if getattr(args, d) is None]
   for i, val in enumerate(args.positionals):
       setattr(args, unfilled[i], val)
   ```
   
   `parse_intermixed_args` (Python 3.7+) allows flags and bare values to be 
freely interspersed, so all of these would work:
   
   ```bash
   airflowctl xcom add d t k                          # all positional
   airflowctl xcom add --dag-id=d --task-id=t --key=k # all flags
   airflowctl xcom add d --task-id=t k                 # mixed
   airflowctl xcom add --task-id=t my_dag my_key       # gap-filling
   ```
   
   The problem is what we lose:
   - **Validation** — can't use `required=True` on flags (argparse would reject 
positional-only usage), so we validate manually after gap-filling
   - **Type checking** — `type=int`, `choices=[...]` etc. don't apply to the 
`nargs='*'` catch-all, so we type-check manually
   - **Help output** — shows `[positionals ...]` instead of named params like 
`DAG_ID TASK_ID`, and no indication which flags are required vs optional
   - **`argparse.REMAINDER`** and **mutually exclusive groups with 
positionals** — unsupported with `parse_intermixed_args`
   
   This effectively means using argparse for flag parsing only and 
reimplementing positional handling on top of it.
   
   </details>


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to