Context construction and anywhere-passable options¶
By default, you wire a context object by assigning ctx.obj manually in the
root group callback:
pyclifer offers a declarative alternative through two features that work together:
context=Trueon@option— marks the option as a context optioncontext_factory=on@app_group— callable that receives context option values and returns thectx.objinstance
Basic usage¶
from pyclifer import app_group, option
from myapp.core.context import MyContext
@app_group(context_factory=MyContext)
@option("--host", required=True, context=True)
@option("--token", required=True, context=True)
def app():
"""My CLI."""
When the CLI starts, pyclifer collects the values of all context=True options
and calls MyContext(host=..., token=...). The result is stored as ctx.obj
before the root callback runs — no manual assignment needed.
Your context class must accept those keyword arguments:
class MyContext(BaseContext):
def __init__(self, host: str = "localhost", token: str | None = None, **kwargs):
super().__init__(**kwargs)
self.client = MyClient(host=host, token=token)
Anywhere-passable placement¶
Context options (and global options marked is_global=True) are anywhere-passable:
they are accepted at any position in the command chain, including after a subcommand name.
All of the following are equivalent:
# canonical position — before the subcommand
myapp --host api.example.com --token secret items list
# after the subcommand
myapp items list --host api.example.com --token secret
# mixed
myapp --host api.example.com items list --token secret
This is useful when users want to keep connection options close to the command
that uses them without breaking the context_factory contract.
Priority¶
Anywhere-passable placement does not change option priority. The standard Click cascade still applies:
If the same option appears both before and after the subcommand boundary, the value closest to the option definition (canonical position) wins.
Difference between context=True and is_global=True¶
| Feature | context=True |
is_global=True |
|---|---|---|
| Accepted anywhere in chain | Yes | Yes |
| Forwarded to subcommand params | No | Yes |
Passed to context_factory |
Yes | No |
Use context=True for options that feed ctx.obj construction (connection
credentials, environment name, etc.). Use is_global=True for cross-cutting
options that each subcommand also receives directly (e.g. --dry-run).
An option can carry both flags if you need both behaviours.
Known limitations¶
nargs=-1 options must stay in canonical position¶
Click does not allow nargs=-1 on options (only on arguments). If you define
a multi-value option with a fixed nargs greater than 1, it must appear before
the subcommand boundary:
# nargs=2 option — works anywhere
myapp items list --coords 10 20
# Correct: values travel as a unit
myapp items list --coords 10 20
A variadic list of values (e.g. --tags a b c) requires a Click Argument
with nargs=-1, which is not an option and therefore cannot be marked
context=True or is_global=True. Use --tag with multiple=True instead:
-- terminator¶
A bare -- in the argument list stops option scanning. Any context=True or
is_global=True tokens after -- are treated as positional arguments by
Click and are not pre-scanned. Place context options before -- when using
this terminator.