#982 / #1078 fixed this for --help, but the same defect applies to every other core flag when given after a task name whose positional arguments are not yet filled: the flag is silently consumed as the positional value and the task runs instead of the flag taking effect.
Version: invoke 3.0.3 (release) and current master. Python 3.13, Windows.
Repro
# tasks.py
from invoke import task
@task
def build(ctx, target):
print(f"BUILDING {target}")
$ invoke build --echo
BUILDING --echo # task RAN; echo mode not enabled
$ invoke build --dry
BUILDING --dry # "dry run" executed for real
$ invoke build --debug
BUILDING --debug
$ invoke build --warn-only
BUILDING --warn-only
All four core flags are swallowed as the value of the still-unfilled target positional. Same happens on current master (verified). The --help case was fixed in #1078 by checking it before the positional branch; that PR's commentary explicitly scoped everything else out ("Unlike other initial-context flags..."), but the remaining flags have exactly the same never-a-valid-positional property — no task legitimately wants the literal string --echo as data.
Why this is worse than it looks
--dry being swallowed means a user who believes they are doing a dry run actually executes destructive tasks against real targets. That's a safety-relevant failure mode, not just an inconvenience.
Proposed direction
Generalize the #1078 approach: before the positional-arg branch in Parser.handle, treat any token matching an initial-context core flag as that flag (setting its value / entering flag state), regardless of pending positionals. If backwards compatibility concerns exist for tasks that genuinely accept e.g. --echo as a task-level flag — note those are matched per-context later anyway, so initial-context handling can stay reserved for core flags.
Happy to send a PR generalizing #1078's fix if maintainers agree on the semantics.
#982 / #1078 fixed this for
--help, but the same defect applies to every other core flag when given after a task name whose positional arguments are not yet filled: the flag is silently consumed as the positional value and the task runs instead of the flag taking effect.Version: invoke 3.0.3 (release) and current master. Python 3.13, Windows.
Repro
All four core flags are swallowed as the value of the still-unfilled
targetpositional. Same happens on currentmaster(verified). The--helpcase was fixed in #1078 by checking it before the positional branch; that PR's commentary explicitly scoped everything else out ("Unlike other initial-context flags..."), but the remaining flags have exactly the same never-a-valid-positional property — no task legitimately wants the literal string--echoas data.Why this is worse than it looks
--drybeing swallowed means a user who believes they are doing a dry run actually executes destructive tasks against real targets. That's a safety-relevant failure mode, not just an inconvenience.Proposed direction
Generalize the #1078 approach: before the positional-arg branch in
Parser.handle, treat any token matching an initial-context core flag as that flag (setting its value / entering flag state), regardless of pending positionals. If backwards compatibility concerns exist for tasks that genuinely accept e.g.--echoas a task-level flag — note those are matched per-context later anyway, so initial-context handling can stay reserved for core flags.Happy to send a PR generalizing #1078's fix if maintainers agree on the semantics.