249

I see more and more commands like this:

$ pip install "splinter[django]"

What do these square brackets do?

Babken Vardanyan
  • 14,090
  • 13
  • 68
  • 87

7 Answers7

166

The syntax that you are using is:

pip install "project[extra]"

In your case, you are installing the splinter package which has the added support for django.

An explanation from @chepner:

pip install splinter django would install two packages named splinter and django.

pip install splinter[django], on the other hand, installs a variant of the splinter package which contains support for django. Note that it has nothing to do with the django package itself, but is just a string defined by the splinter package for a particular feature set that gets enabled. How the argument django is interpreted is entirely up to its setup.py file.

Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
Joe Iddon
  • 20,101
  • 7
  • 33
  • 54
  • 3
    Care to expand on your answer so future users can benefit? For example what does `extra` mean? – Babken Vardanyan Oct 16 '17 at 17:12
  • Ok, how is this different from `pip install splinter django`? – Babken Vardanyan Oct 16 '17 at 17:13
  • 11
    @BabkenVardanyan That command would install two packages named `splinter` and `django`. `splinter[django]`, on the other hand, installs a variant of the `splinter` package which contains support for `django`. Note that it has nothing to do with the `django` package itself, but is just a string defined by the `splinter` package for a particular feature set that gets enabled. – chepner Oct 16 '17 at 17:16
  • @chepner Cool, now add a proper answer so future users can benefit. – Babken Vardanyan Oct 16 '17 at 17:18
  • @chepner That explanation was much clearer than anything I could find elsewhere so I added it to the answer! – Joe Iddon Oct 16 '17 at 17:22
  • @chepner So this is just a naming convention, and the `splinter[django]` is an actual package name? Or is there more going on here? – jpmc26 Oct 16 '17 at 23:23
  • 8
    `splinter` is still the package name; `pip` itself parses `splinter[django]` and recognizes it as a package name with an extra "argument" to help it install the correct files. How the argument `django` is interpreted is entirely up to the `setup.py` file (or some other config file? I don't actually know the details) used to define the package `splinter`. – chepner Oct 16 '17 at 23:26
  • @JoeIddon Your answer's first part still conflicts with the second part that's why I am not accepting it. First part insists that django package is installed, while second part contradicts it. Please fix your answer. – Babken Vardanyan Oct 17 '17 at 10:12
  • 1
    I believe the only thing the [extra] syntax does is specify additional from extras_requires that will be installed. That is, `pip install splinter` will install fewer requirements than `pip install splinter[django]`. The additional packages that are installed may indeed (and probably do) enable additional features of splinter to work, but it doesn't change anything about the splinter package itself. It just tells pip about additional dependencies. – William Pursell Jan 12 '18 at 19:26
  • Strange, I searched splinter[django] on PyPI and the result shows:Index of Packages Matching 'splinterdjango' There were no matches. – tribbloid Jan 22 '18 at 01:43
  • Never thought I'd have to use this 'till today, thanks for clearing it up! – Malekai Jun 10 '19 at 19:25
  • Very often, we should notice the quotes ``pip install "project[extra]"``. Without the quotes, it causes problems in some shells because ``[]`` is a special syntax for them. – youkaichao Aug 28 '19 at 20:42
  • 21
    I think this answer is incorrect. This does not install a "splinter[django]" package, but rather both splinter and Django projects. These are setuptools extras as explained in answers by @paul and prosti – user1523170 Sep 20 '19 at 20:25
  • 2
    I don't think this answer is correct. Look at [elasticsearch](https://github.com/elastic/elasticsearch-py/blob/master/setup.py) package. It has an `elasticsearch[async]` flavor which contains the exact same code as when installing `elasticsearch`, but simply installs `aiohttp` in addition to make sure using the async classes works well. There is no separate `elasticsearch[async]` package – Dean Gurvitz Jul 04 '21 at 14:34
  • 2
    "Really, you are installing the package named: 'splinter[django]'." <- I don't think this is correct. I just ran `pip install splinter[django]`, and `pip freeze` doesn't show any package name called splinter[django] but rather the packages splinter and django separatedly. – Simon Ernesto Cardenas Zarate Dec 09 '21 at 03:46
  • Here is more correct solution: https://stackoverflow.com/a/60307740/9913319 – Rufat Dec 06 '22 at 07:30
126

Brackets [optional] in PIP signify optional dependencies

Just in case another developer comes along looking to implement this pattern in their own Python package deployment, here's further explanation of the brackets [] in pip.

For Example: Apache Airflow

To install airflow from pip we use this command:

pip install 'apache-airflow'

You can install optional components of airflow with:

pip install 'apache-airflow[aws]'
#      [optional] -----------^

When we search pypi for apache-airflow note that the optional packages do not show up:

pip search 'apache-airflow'

apache-airflow (1.10.9)                            - Programmatically author, schedule and monitor data pipelines
pylint-airflow (0.1.0a1)                           - A Pylint plugin to lint Apache Airflow code.
swe-airflow-tools (0.0.3)                          - Tools for Apache Airflow Application
airflow (0.6)                                      - Placeholder for the old Airflow package
...

Implementation via setup.py

You can see how this was accomplished in the setup.py script
On the left in setup.py - extras_require is defined.
On the right are the correlated installation commands for these optional sub-packages.

setup.py vs install

Ben DeMott
  • 3,362
  • 1
  • 25
  • 35
31

Pretty sure these are setuptools extras:

https://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-extras-optional-features-with-their-own-dependencies

Sometimes a project has “recommended” dependencies, that are not required for all uses of the project. For example, a project might offer optional PDF output if ReportLab is installed, and reStructuredText support if docutils is installed. These optional features are called “extras” ...

Paul
  • 1,192
  • 1
  • 11
  • 23
28

Maybe worthwhile to know that this optional package syntax admits multiple extras (separated by comma within the brackets) as in:

python -m pip install SomePackage[PDF,EPUB]  # multiple extras

As per the pip manual

SeriousFun01
  • 321
  • 3
  • 6
  • 1
    But could I query how many those “recommended” dependencies are available? And especially, are all of them independent and combinable/compatible with each other? Could I just install all of them, something like `pip install package[*] `? – Severin Pappadeux Feb 18 '21 at 16:45
12

TLDR

The square bracket contains the 'extra' option's information defined in setup.py that pip will use to install additional dependencies.

pip install "splinter[django]"

To be specific, the above line will install first the 'splinter' package, then install the extra dependencies the 'splinter' project requires with the 'django' option specified in a setup.py of 'splinter' project.

Explanation

pip install "splinter[django]" 

pip install "splinter" "Django>=2.0.6" "lxml>=4.2.4" "cssselect"

As of splinter==0.16.0, with python==3.9.2, the above two commands are equivalent.

Both pip install will result in the following packages given a clean virtual enviroment.

enter image description here

The reason why the two pip install commands achieve same is because this is literally what has been run in the background based on the setup.py of the splinter package enter image description here

The '[django]' is the 'extra' option for the 'splinter' package. Pip will look into the setup.py of splinter package, and find what needs to be installed with the '[django]' option specified. In this case, it is these 3 packages: ["Django>=2.0.6", "lxml>=4.2.4", "cssselect"]

alson_y
  • 173
  • 2
  • 9
  • [Prefer text, not images](https://meta.stackoverflow.com/questions/285551/why-should-i-not-upload-images-of-code-data-errors) – ggorlen Mar 25 '23 at 03:08
  • @ggorlen Imho, in this particular case, the image is way more informative than the text would be. – Antony Hatchkins Jun 16 '23 at 03:55
  • @AntonyHatchkins If you had a data limit, a visual impairment or a corporate firewall or you wanted to zoom the text or copy and paste something from the answer, or use the site with consistent dark mode and consistent fonts, you'd probably feel differently. I'm not sure what value the images are adding here. They're just screenshots of text. If every answer looked like this, the site would be nigh-unusable. Please read [the provided link](https://meta.stackoverflow.com/questions/285551/why-should-i-not-upload-images-of-code-data-errors). It's the site standard. – ggorlen Jun 16 '23 at 05:23
  • @ggorlen--onLLMstrike I agree about the first image. Absolutely no reason to use an image here. As for the second one, it is a limitation of the markdown subset used by SO: markdown and HTML tags are ignored within code blocks. And in this particular case highlighting the most relevant part of the huge block of text is absolutely helpful while providing no context at, all as done in the other answers, makes it less evident for the reader. As for me, I've even used the ascii-art in my answers to alleviate the issue :) but here I'd vote for an image — with a shorter text version in the alt tag. – Antony Hatchkins Jun 16 '23 at 07:03
6

This is exactly the list from the setup.py file for the project in question:

"django": ["Django>=1.7.11;python_version<'3.0'", "Django>=2.0.6;python_version>'3.3'", "lxml>=2.3.6", "cssselect", "six"],
prosti
  • 42,291
  • 14
  • 186
  • 151
0

Except extras_require in setup.py, this extra dependences maybe specified in [project.optional-dependencies] of pyproject.toml too.

see https://github.com/reactive-python/reactpy/blob/403e5f24536808218c511ed0ee0438fd6e1b94c8/src/py/reactpy/pyproject.toml#L38-L65.

Donghua Liu
  • 1,776
  • 2
  • 21
  • 30