skip to content

What does `pip install mypkg[redis]` do, and where is that extra declared?

level: juniorimportance: must knowfreq 55%

answer

  1. Brackets after the name at install time
  2. An opt-in bundle, declared by the package
  3. Lives in a pyproject.toml table
  4. Adds requirements, never removes them
  5. Provides-Extra plus an extra == marker

basics

~20 s

It installs mypkg itself plus the optional dependency set named redis. That set is declared in the project's pyproject.toml under the [project.optional-dependencies] table, where each key is an extra name and its value is a list of requirement strings.

solid answer

~40 s

The bracketed name is an **extra**: a named, optional dependency set the distribution declares about itself. In `pyproject.toml` it lives in `[project.optional-dependencies]`, e.g. `redis = ["a-redis-client>=5"]`. `pip install mypkg[redis]` installs `mypkg` **and** everything under that key; the base package is always installed too, never replaced. Several extras combine as `mypkg[redis,postgres]`, and the brackets must be quoted in a shell that globs. Extras are additive only — an extra can add requirements but cannot remove or loosen one already in `[project] dependencies`. In the built wheel they appear as `Provides-Extra:` lines plus `Requires-Dist:` entries carrying an `extra == "redis"` environment marker, which is how an installer knows which requirements to pull in.

code

console · 1 line
console
python -m pip install "mypkg[redis,postgres]"

go deeper

for a junior

Recall the two halves: brackets at install time select an extra, and the extra is declared in pyproject.toml under [project.optional-dependencies]. Also remember the base package is always installed alongside it, and quote the brackets in a shell.

for a middle

Be ready to explain the mechanics: each extra becomes a Provides-Extra line plus Requires-Dist entries carrying an extra == "name" marker, which is why extras only ever add requirements. Mention name normalization and the comma-separated multi-extra form.

for a senior

An interviewer expects you to connect the metadata to operational reality: extras are published to every consumer, cannot be negated, are fixed per release, and leave no runtime record, so optional features need a guarded import that fails with the exact install command.

for a principal

Own the policy angle. The set of extras you publish is a long-lived API promise — each one multiplies the install configurations you must test and support, and moving a dependency between base and extra is a breaking change for someone. Decide deliberately how many exist.

### What an extra actually is An **extra** is a named bundle of *optional* dependencies that a distribution declares about itself, and that a consumer opts into when installing. It is metadata on the package, not a feature of the Python language or of any particular interpreter version. The point is that the default install stays small: everyone gets the core requirements, and only the people who need the optional integration pay for its dependency tree. ### Where it is declared Since PEP 621 the declaration lives in `pyproject.toml`, in a table whose full name is `[project.optional-dependencies]`. Each key is an extra name; each value is a list of ordinary requirement strings, exactly the same grammar you would write in `[project] dependencies`: ```toml [project] name = "payroll-import" version = "1.0.0" dependencies = ["a-csv-schema-lib>=2"] [project.optional-dependencies] fast = ["a-fast-parser>=1.4"] excel = ["a-spreadsheet-reader"] all = ["payroll-import[fast,excel]"] ``` The `all` key shows the common **meta-extra** pattern: an extra whose only requirement is the project itself with other extras selected. Self-referential extras are understood by current installers and save consumers from having to list every extra by hand. ### What the install command does `pip install "payroll-import[fast]"` resolves and installs the distribution `payroll-import` **plus** the requirements listed under its `fast` key. Two points trip people up. First, the base package is always installed as well — the brackets *add*, they do not select a subset. Second, several extras are comma-separated inside one pair of brackets: `payroll-import[fast,excel]`. Quote the argument: `zsh` treats bare brackets as a glob pattern and refuses the command with "no matches found", and quoting is harmless everywhere else. The same syntax works wherever a requirement string is accepted — a `requirements.txt` line, a `[project] dependencies` entry in a downstream project, or an editable install of a local checkout (`pip install -e ".[fast]"`). ### How the metadata encodes it When the wheel or sdist is built, each extra name becomes a `Provides-Extra:` line in the distribution's `METADATA`, and every requirement under that key becomes a `Requires-Dist:` line carrying the environment marker `extra == "<name>"`. So `fast = ["a-fast-parser>=1.4"]` becomes roughly: ``` Provides-Extra: fast Requires-Dist: a-fast-parser>=1.4; extra == "fast" ``` An installer evaluates that marker as true only when the extra was requested. This is why extras are purely additive: a marked requirement can be *switched on*, never switched off, and there is no mechanism by which selecting an extra removes or downgrades a base requirement. If a dependency must be present in one configuration and absent in another, that is two different distributions or an environment marker on a base requirement — not an extra. It is also why extras are visible to the world. Anything you declare as an extra ships in the published metadata and any consumer can install it, which is exactly why development-only tooling was eventually given its own mechanism (`[dependency-groups]`, PEP 735) rather than being smuggled into a `dev` extra. ### Name normalization Extra names are normalized: lowercased, with each run of `-`, `_` or `.` collapsed to a single `-` (PEP 685). So `Fast_Parse`, `fast.parse` and `fast-parse` all name the same extra, and an installer matches the request against the declaration after normalizing both. That removes one class of mismatch, but it does not save you from an outright typo — `[fastt]` is simply an extra the distribution does not provide. ### What extras do not give you There is no runtime API that reports which extras were requested at install time; the request is not recorded anywhere on the installed distribution. `importlib.metadata.metadata("mypkg").get_all("Provides-Extra")` tells you which extras the package *declares*, not which were selected. Code that needs to know whether an optional feature is available therefore probes for the module — a guarded import, or `importlib.util.find_spec` — and raises an error naming the exact install command when it is missing. Extras also do not version independently. They are part of the distribution's metadata, so the set of extras a release provides is fixed at build time; adding an extra requires a new release, and removing one is a breaking change for anyone whose install command names it. ### Where else the bracket syntax appears An extra is part of a requirement string, so it works anywhere one is accepted, not only on the command line. A downstream project can write `"payroll-import[fast]>=2"` in its own `[project] dependencies`, and the extra propagates: installing that project pulls in `payroll-import` with its `fast` requirements. The same string is valid in a `requirements.txt` line and in an editable install of a local checkout, `pip install -e ".[fast]"`, where the leading dot is the project directory and the brackets select its extras. Because the syntax is uniform, a library that publishes a well-named extra makes it easy for consumers to express "I need that feature" once, in metadata, rather than in a deployment script.

  • Can an extra remove or downgrade something already listed in the project's base dependencies?
    No. Every requirement under an extra becomes a `Requires-Dist` line guarded by an `extra == "name"` marker, so requesting the extra can only switch additional requirements on. There is no negative form. If a dependency should be absent in some configuration, express that with an environment marker on the base requirement, or ship a separate distribution — an extra cannot do it.
  • Is the extra `Fast_Parse` the same as `fast-parse`?
    Yes. PEP 685 normalizes extra names by lowercasing and collapsing each run of `-`, `_` or `.` into a single `-`, on both the declaration and the request, so those two names refer to one extra. Normalization does not rescue a genuine misspelling: an extra the distribution never declared is simply unknown, and pip warns rather than failing.
  • Can your code ask at runtime which extras the user installed?
    No — the selection is not recorded on the installed distribution. `importlib.metadata.metadata(name).get_all("Provides-Extra")` lists the extras a package *declares*, not those that were requested. To decide whether an optional feature is usable, probe for the module itself with a guarded import or `importlib.util.find_spec`, and raise an error that names the exact install command when it is absent.

Extras are the option packs on a car order form: the base model always ships, you tick the packs you want, and no pack lets you remove the engine.

saying these in an interview costs you the question

  • Thinks pkg[extra] installs only the extra, not pkg itself
  • Says extras are installed by default unless disabled
  • Believes an extra can drop or downgrade a base dependency
  • Confuses an extra with a PEP 735 dependency group
  • Assumes pip errors out on an extra the package never declared
  • Claims code can query at runtime which extras were selected

context