Installing Python Modules¶
As a popular open source development project, Python has an active supporting community of contributors and users that also make their software available for other Python developers to use under open source license terms.
This allows Python users to share and collaborate effectively, benefiting from the solutions others have already created to common (and sometimes even rare!) problems, as well as potentially contributing their own solutions to the common pool.
This guide covers the installation part of the process. For a guide to creating and sharing your own Python projects, refer to the distribution guide .
For corporate and other institutional users, be aware that many organisations have their own policies around using and contributing to open source software. Please take such policies into account when making use of the distribution and installation tools provided with Python.
Key terms¶
pip is the preferred installer program. Starting with Python 3.4, it is included by default with the Python binary installers.
A virtual environment is a semi-isolated Python environment that allows packages to be installed for use by a particular application, rather than being installed system wide.
venv is the standard tool for creating virtual environments, and has been part of Python since Python 3.3. Starting with Python 3.4, it defaults to installing pip into all created virtual environments.
virtualenv is a third party alternative (and predecessor) to venv . It allows virtual environments to be used on versions of Python prior to 3.4, which either don’t provide venv at all, or aren’t able to automatically install pip into created environments.
The Python Package Index is a public repository of open source licensed packages made available for use by other Python users.
the Python Packaging Authority is the group of developers and documentation authors responsible for the maintenance and evolution of the standard packaging tools and the associated metadata and file format standards. They maintain a variety of tools, documentation, and issue trackers on both GitHub and Bitbucket.
distutils is the original build and distribution system first added to the Python standard library in 1998. While direct use of distutils is being phased out, it still laid the foundation for the current packaging and distribution infrastructure, and it not only remains part of the standard library, but its name lives on in other ways (such as the name of the mailing list used to coordinate Python packaging standards development).
Changed in version 3.5: The use of venv is now recommended for creating virtual environments.
Basic usage¶
The standard packaging tools are all designed to be used from the command line.
The following command will install the latest version of a module and its dependencies from the Python Package Index:
For POSIX users (including macOS and Linux users), the examples in this guide assume the use of a virtual environment .
For Windows users, the examples in this guide assume that the option to adjust the system PATH environment variable was selected when installing Python.
It’s also possible to specify an exact or minimum version directly on the command line. When using comparator operators such as > , < or some other special character which get interpreted by shell, the package name and the version should be enclosed within double quotes:
Normally, if a suitable module is already installed, attempting to install it again will have no effect. Upgrading existing modules must be requested explicitly:
More information and resources regarding pip and its capabilities can be found in the Python Packaging User Guide.
Creation of virtual environments is done through the venv module. Installing packages into an active virtual environment uses the commands shown above.
How do I …?¶
These are quick answers or links for some common tasks.
… install pip in versions of Python prior to Python 3.4?¶
Python only started bundling pip with Python 3.4. For earlier versions, pip needs to be “bootstrapped” as described in the Python Packaging User Guide.
… install packages just for the current user?¶
Passing the —user option to python -m pip install will install a package just for the current user, rather than for all users of the system.
… install scientific Python packages?¶
A number of scientific Python packages have complex binary dependencies, and aren’t currently easy to install using pip directly. At this point in time, it will often be easier for users to install these packages by other means rather than attempting to install them with pip .
… work with multiple versions of Python installed in parallel?¶
On Linux, macOS, and other POSIX systems, use the versioned Python commands in combination with the -m switch to run the appropriate copy of pip :
Appropriately versioned pip commands may also be available.
On Windows, use the py Python launcher in combination with the -m switch:
Common installation issues¶
Installing into the system Python on Linux¶
On Linux systems, a Python installation will typically be included as part of the distribution. Installing into this Python installation requires root access to the system, and may interfere with the operation of the system package manager and other components of the system if a component is unexpectedly upgraded using pip .
On such systems, it is often better to use a virtual environment or a per-user installation when installing packages with pip .
Pip not installed¶
It is possible that pip does not get installed by default. One potential fix is:
There are also additional resources for installing pip.
Installing binary extensions¶
Python has typically relied heavily on source based distribution, with end users being expected to compile extension modules from source as part of the installation process.
With the introduction of support for the binary wheel format, and the ability to publish wheels for at least Windows and macOS through the Python Package Index, this problem is expected to diminish over time, as users are more regularly able to install pre-built extensions rather than needing to build them themselves.
Some of the solutions for installing scientific software that are not yet available as pre-built wheel files may also help with obtaining other binary extensions without needing to build them locally.
pip install#
PyPI (and other indexes) using requirement specifiers.
VCS project urls.
Local project directories.
Local or remote source archives.
pip also supports installing from “requirements files”, which provide an easy way to specify a whole environment to be installed.
Overview#
pip install has several stages:
Identify the base requirements. The user supplied arguments are processed here.
Resolve dependencies. What will be installed is determined here.
Build wheels. All the dependencies that can be are built into wheels.
Install the packages (and uninstall anything being upgraded/replaced).
Note that pip install prefers to leave the installed version as-is unless —upgrade is specified.
Argument Handling#
When looking at the items to be installed, pip checks what type of item each is, in the following order:
Project or archive URL.
Local directory (which must contain a setup.py , or pip will report an error).
Local file (a sdist or wheel format archive, following the naming conventions for those formats).
A requirement, as specified in PEP 440.
Each item identified is added to the set of requirements to be satisfied by the install.
Working Out the Name and Version#
For each candidate item, pip needs to know the project name and version. For wheels (identified by the .whl file extension) this can be obtained from the filename, as per the Wheel spec. For local directories, or explicitly specified sdist files, the setup.py egg_info command is used to determine the project metadata. For sdists located via an index, the filename is parsed for the name and project version (this is in theory slightly less reliable than using the egg_info command, but avoids downloading and processing unnecessary numbers of files).
Any URL may use the #egg=name syntax (see VCS Support ) to explicitly state the project name.
Satisfying Requirements#
Once pip has the set of requirements to satisfy, it chooses which version of each requirement to install using the simple rule that the latest version that satisfies the given constraints will be installed (but see here for an exception regarding pre-release versions). Where more than one source of the chosen version is available, it is assumed that any source is acceptable (as otherwise the versions would differ).
Obtaining information about what was installed#
The install command has a —report option that will generate a JSON report of what pip has installed. In combination with the —dry-run and —ignore-installed it can be used to resolve a set of requirements without actually installing them.
The report can be written to a file, or to standard output (using —report — in combination with —quiet ).
The format of the JSON report is described in Installation Report .
Installation Order#
This section is only about installation order of runtime dependencies, and does not apply to build dependencies (those are specified using PEP 518).
As of v6.1.0, pip installs dependencies before their dependents, i.e. in “topological order.” This is the only commitment pip currently makes related to order. While it may be coincidentally true that pip will install things in the order of the install arguments or in the order of the items in a requirements file, this is not a promise.
In the event of a dependency cycle (aka “circular dependency”), the current implementation (which might possibly change later) has it such that the first encountered member of the cycle is installed last.
For instance, if quux depends on foo which depends on bar which depends on baz, which depends on foo:
Prior to v6.1.0, pip made no commitments about install order.
The decision to install topologically is based on the principle that installations should proceed in a way that leaves the environment usable at each step. This has two main practical benefits:
Concurrent use of the environment during the install is more likely to work.
A failed install is less likely to leave a broken environment. Although pip would like to support failure rollbacks eventually, in the mean time, this is an improvement.
Although the new install order is not intended to replace (and does not replace) the use of setup_requires to declare build dependencies, it may help certain projects install from sdist (that might previously fail) that fit the following profile:
They have build dependencies that are also declared as install dependencies using install_requires .
python setup.py egg_info works without their build dependencies being installed.
For whatever reason, they don’t or won’t declare their build dependencies using setup_requires .
Requirements File Format
This section has been moved to Requirements File Format .
This section has been moved to Requirement Specifiers .
Pre-release Versions#
Starting with v1.4, pip will only install stable versions as specified by pre-releases by default. If a version cannot be parsed as a compliant PEP 440 version then it is assumed to be a pre-release.
If a Requirement specifier includes a pre-release or development version (e.g. >=0.0.dev0 ) then pip will allow pre-release and development versions for that requirement. This does not include the != flag.
The pip install command also supports a —pre flag that enables installation of pre-releases and development releases.
This is now covered in VCS Support .
Finding Packages#
pip searches for packages on PyPI using the HTTP simple interface, which is documented here and there.
pip offers a number of package index options for modifying how packages are found.
pip looks for packages in a number of places: on PyPI (if not disabled via —no-index ), in the local filesystem, and in any additional repositories specified via —find-links or —index-url . There is no ordering in the locations that are searched. Rather they are all checked, and the “best” match for the requirements (in terms of version number — see PEP 440 for details) is selected.
SSL Certificate Verification
This is now covered in HTTPS Certificates .
This is now covered in Caching .
This is now covered in Caching .
Hash checking mode
This is now covered in Secure installs .
Local Project Installs
Build System Interface
Options#
-r , —requirement <file> #
Install from the given requirements file. This option can be used multiple times.
-c , —constraint <file> #
Constrain versions using the given constraints file. This option can be used multiple times.
Don’t install package dependencies.
Include pre-release and development versions. By default, pip only finds stable versions.
-e , —editable <path/url> #
Install a project in editable mode (i.e. setuptools “develop mode”) from a local project path or a VCS url.
Don’t actually install anything, just print what would be. Can be used in combination with —ignore-installed to ‘resolve’ the requirements.
Install packages into <dir>. By default this will not replace existing files/folders in <dir>. Use —upgrade to replace existing packages in <dir> with new versions.
Only use wheels compatible with <platform>. Defaults to the platform of the running system. Use this option multiple times to specify multiple platforms supported by the target interpreter.
The Python interpreter version to use for wheel and “Requires-Python” compatibility checks. Defaults to a version derived from the running interpreter. The version can be specified using up to three dot-separated integers (e.g. “3” for 3.0.0, “3.7” for 3.7.0, or “3.7.3”). A major-minor version can also be given as a string without dots (e.g. “37” for 3.7.0).
Only use wheels compatible with Python implementation <implementation>, e.g. ‘pp’, ‘jy’, ‘cp’, or ‘ip’. If not specified, then the current interpreter implementation is used. Use ‘py’ to force implementation-agnostic wheels.
Only use wheels compatible with Python abi <abi>, e.g. ‘pypy_41’. If not specified, then the current interpreter abi tag is used. Use this option multiple times to specify multiple abis supported by the target interpreter. Generally you will need to specify —implementation, —platform, and —python-version when using this option.
Install to the Python user install directory for your platform. Typically
/.local/, or %APPDATA%Python on Windows. (See the Python documentation for site.USER_BASE for full details.)
Install everything relative to this alternate root directory.
Installation prefix where lib, bin and other top-level folders are placed
Directory to check out editable projects into. The default in a virtualenv is “<venv path>/src”. The default for global installs is “<current dir>/src”.
Upgrade all specified packages to the newest available version. The handling of dependencies depends on the upgrade-strategy used.
Determines how dependency upgrading should be handled [default: only-if-needed]. “eager” — dependencies are upgraded regardless of whether the currently installed version satisfies the requirements of the upgraded package(s). “only-if-needed” — are upgraded only when they do not satisfy the requirements of the upgraded package(s).
Reinstall all packages even if they are already up-to-date.
Ignore the installed packages, overwriting them. This can break your system if the existing package is of a different version or was installed with a different package manager!
Ignore the Requires-Python information.
Disable isolation when building a modern source distribution. Build dependencies specified by PEP 518 must be already installed if this option is used.
Use PEP 517 for building source distributions (use —no-use-pep517 to force legacy behaviour).
Check the build dependencies when PEP517 is used.
Allow pip to modify an EXTERNALLY-MANAGED Python installation
Configuration settings to be passed to the PEP 517 build backend. Settings take the form KEY=VALUE. Use multiple —config-settings options to pass multiple keys to the backend.
This option is deprecated. Using this option with location-changing options may cause unexpected behavior. Use pip-level options like —user, —prefix, —root, and —target.
Extra global options to be supplied to the setup.py call before the install or bdist_wheel command.
Compile Python source files to bytecode
Do not compile Python source files to bytecode
Do not warn when installing scripts outside PATH
Do not warn about broken dependencies
Do not use binary packages. Can be supplied multiple times, and each time adds to the existing value. Accepts either “:all:” to disable all binary packages, “:none:” to empty the set (notice the colons), or one or more package names with commas between them (no colons). Note that some packages are tricky to compile and may fail to install when this option is used on them.
Do not use source packages. Can be supplied multiple times, and each time adds to the existing value. Accepts either “:all:” to disable all source packages, “:none:” to empty the set, or one or more package names with commas between them. Packages without binary distributions will fail to install when this option is used on them.
Prefer older binary packages over newer source packages.
Require a hash to check each requirement against, for repeatable installs. This option is implied when any package in a requirements file has a —hash option.
Specify whether the progress bar should be used [on, off] (default: on)
Action if pip is run as a root user. By default, a warning message is shown.
Generate a JSON file describing what pip did to install the provided requirements. Can be used in combination with —dry-run and —ignore-installed to ‘resolve’ the requirements. When — is used as file name it writes to stdout. When writing to stdout, please combine with the —quiet option to avoid mixing pip logging output with JSON output.
Don’t clean up build directories.
Base URL of the Python Package Index (default https://pypi.org/simple). This should point to a repository compliant with PEP 503 (the simple repository API) or a local directory laid out in the same format.
Extra URLs of package indexes to use in addition to —index-url. Should follow the same rules as —index-url.
Ignore package index (only looking at —find-links URLs instead).
If a URL or path to an html file, then parse for links to archives such as sdist (.tar.gz) or wheel (.whl) files. If a local path or file:// URL that’s a directory, then look for archives in the directory listing. Links to VCS project URLs are not supported.
Examples#
Install SomePackage and its dependencies from PyPI using Requirement Specifiers
Основы
В Python ключевое слово import применяется для того, чтобы сделать код в одном модуле доступным для работы в другом. Импорт в Python важен для эффективного структурирования кода. Правильное применение импорта повысит вашу продуктивность: вы сможете повторно использовать код и при этом продолжать осуществлять поддержку своих проектов.
В статье представлен подробный обзор инструкции import в Python и того, как она работает. Здесь мощная система импорта. Вам предстоит узнать, как эту мощь задействовать, а также изучить ряд понятий, лежащих в основе системы импорта в Python. Их изложение в статье построено главным образом на примерах (в помощь вам будут несколько примеров кода).
В этой статье вы узнаете, как:
- Работать с модулями, пакетами и пакетами пространств имён.
- Импортировать ресурсы и файлы данных внутри ваших пакетов.
- Динамически импортировать модули во время выполнения.
- Настраивать систему импорта в Python.
На протяжении всей статьи даются примеры: вы сможете поэкспериментировать с тем, как организован импорт в Python, чтобы работать наиболее эффективно. Хотя в статье показан весь код, имеется также возможность скачать его по ссылке ниже:
Базовый импорт Python
Код в Python организован в виде модулей и пакетов. В этой части статьи мы объясним, чем они отличаются друг от друга и как с ними можно работать.
Чуть дальше вы узнаете о нескольких продвинутых и менее известных примерах применения системы импорта в Python. Но начнём с основ — импортирования модулей и пакетов.
Модули
В Python.org glossary даётся следующее определение модуля:
Объект, который служит организационной единицей кода в Python. Модули имеют пространство имён, в котором содержатся произвольные объекты Python. Модули загружаются в Python посредством импортирования. (Источник)
На практике модуль соответствует, как правило, одному файлу с расширением .py . В этом файле содержится код на Python.
Модули обладают сверхспособностью импортироваться и повторно использоваться в другом коде. Рассмотрим следующий пример:
В первой строке import math вы импортируете код в модуль math и делаете его доступным для использования. Во второй строке вы получаете доступ к переменной в модуле math . Модуль math является частью стандартной библиотеки Python, поэтому он всегда доступен для импорта, когда вы работаете с Python.
Обратите внимание, что пишется не просто pi , а math.pi .
math — это не только модуль, а ещё и пространство имён, в котором содержатся все атрибуты этого модуля. Пространства имён важны для читаемости и структурированности кода.
Содержимое пространства имён можно посмотреть с помощью dir() :
Если не указывать при этом никаких аргументов, т.е. напечатать просто dir() , то можно увидеть, что находится в глобальном пространстве имён. Посмотреть содержимое пространства имён math можно, указав его в качестве аргумента вот так: dir(math) .
Вы уже видели самый простой способ импортирования. Есть и другие, которые позволяют импортировать отдельные части модуля и переименовывать его в процессе импортирования.
Вот код, который импортирует из модуля math только переменную pi :
Обратите внимание, что pi помещается в глобальное пространство имён, а не в пространство имён math .
А вот как в процессе импортирования переименовываются модули и атрибуты:
Пакеты
Пакет представляет собой следующий после модуля уровень в организационной иерархии кода. В Python.org glossary даётся следующее определение пакета:
Это модуль Python, который может содержать подмодули или (рекурсивно) подпакеты. Строго говоря, пакет — это модуль Python с атрибутом __path__ . (Источник.)
То есть пакет — это тоже модуль. Пользователю обычно не приходится задумываться о том, что у него импортируется: модуль или пакет.
На практике пакет — это, как правило, каталог файлов, внутри которого находятся файлы Python и другие каталоги. Чтобы создать пакет Python самостоятельно, создайте каталог, а внутри него — файл с именем __init__.py . В __init__.py файле находится содержимое этого пакета-модуля. И он может быть пустым.
Обратите внимание: каталоги без файла __init__.py Python всё равно считает пакетами. Но это уже будут не обычные пакеты, а то, что можно назвать пакетами пространства имён. Подробнее о них чуть дальше в статье.
Вообще подмодули и подпакеты нельзя импортировать вместе с пакетом. Это можно сделать с помощью __init__.py , включив любой или все подмодули и подпакеты, если захотите. В качестве примера создадим пакет для Hello world на разных языках. Пакет будет состоять из следующих каталогов и файлов:
Для файла каждой страны выводится соответствующее приветствие, а файлы __init__.py выборочно импортируют некоторые подпакеты и подмодули. Вот точное содержимое этих файлов:
Обратите внимание: world/__init__.py импортирует только africa , а не europe ; world/africa/__init__.py ничего не импортирует; world/europe/__init__.py импортирует greece и norway , а не spain . Модуль каждой страны при импортировании выводит приветствие.
Разберёмся, как ведут себя подпакеты и подмодули в пакете world :
При импортировании europe модули europe.greece и europe.norway тоже импортируются. Это происходит потому, что модули этих стран выводят приветствие при импортировании:
Файл world/africa/__init__.py пуст. Это означает, что импортирование пакета world.africa создаёт пространство имён, но этим и ограничивается:
Не забывайте: при импорте модуля загружается его содержимое и одновременно создаётся пространство имён с этим содержимым. Последние несколько примеров показывают, что один и тот же модуль может быть частью разных пространств имён.
Технические нюансы: пространство имён модуля реализовано в виде словаря Python и доступно в атрибуте .__dict__ :
Но вам не придётся часто взаимодействовать с .__dict__ напрямую.
Глобальное пространство имён в Python тоже является словарём. Доступ к нему можно получить через globals() .
Импортировать подпакеты и подмодули в файле __init__.py — это обычное дело. Так они становятся более доступными для пользователей. Вот вам пример того, как это происходит в популярном пакете запросов.
Абсолютный и относительный импорт
Напомним исходный код world/__init__.py предыдущего примера:
Чуть ранее мы уже разбирали операторы типа from. import , такие как from math import pi . Что же означает точка ( . ) в from . import africa ?
Точка указывает на текущий пакет, а сам оператор — это пример относительного импорта. Можно прочитать этот
так: «из текущего пакета импортируется подпакет africa ».
Существует эквивалентный ему оператор абсолютного импорта, в котором прямо указывается название этого текущего пакета:
На самом деле, все импорты в world можно было бы сделать в виде таких вот абсолютных импортов с указанием названия текущего пакета.
Относительные импорты должны иметь такую from. import форму, причём обозначение места, откуда вы импортируете, должно начинаться с точки.
В руководстве по стилю PEP 8 рекомендуется в основном абсолютный импорт. Однако относительный импорт в качестве альтернативы абсолютному тоже имеет право на существование при организации иерархии пакетов.
Путь импорта в Python
А как Python находит модули и пакеты, которые импортирует? Более подробно о специфике системы импорта в Python расскажем чуть дальше в статье. А пока нам достаточно просто знать, что Python ищет модули и пакеты в своём пути импорта. Это такой список адресов, по которым выполняется поиск модулей для импорта.
Примечание: когда вы вводите import чего-то (что надо импортировать) , Python будет искать это что-то в нескольких разных местах, прежде чем переходить к поиску пути импорта.
Так, он заглянет в кэш модулей и проверит, не было ли это что-то уже импортировано, а также проведёт поиск среди встроенных модулей.
Подробнее о том, как организован импорт в Python, расскажем чуть дальше в статье.
Путь импорта в Python можно просмотреть, выведя на экран sys.path . В этом списке будет три различных типа адресов:
- Каталог текущего скрипта или текущий каталог, если скрипта нет (например, когда Python работает в интерактивном режиме).
- Содержимое переменной окружения PYTHONPATH .
- Другие каталоги, зависящие от конкретной системы.
Поиск Python, как правило, стартует в начале списка адресов и проходит по всем адресам до первого совпадения с искомым модулем. Каталог скрипта или текущий каталог всегда идёт первым в этом списке. Поэтому можно организовать каталоги так, чтобы скрипты находили ваши самодельные модули и пакеты. При этом надо внимательно следить за тем, из какого каталога вы запускаете Python.
Стоит следить и за тем, чтобы не создавались модули, которые затеняют или скрывают другие важные модули. В качестве примера предположим, что вы определяете следующий модуль math :
Всё пока идёт как надо:
Вот только модуль этот затеняет модуль math , который входит в состав стандартной библиотеки. Это приводит к тому, что наш предыдущий пример поиска значения π больше не работает:
Вместо того, чтобы искать модуль math в стандартной библиотеке, Python теперь ищет ваш новый модуль math для pi .
Во избежание подобных проблем надо быть осторожным с названиями модулей и пакетов. Имена модулей и пакетов верхнего уровня должны быть уникальными. Если math определяется как подмодуль внутри пакета, то он не будет затенять встроенный модуль.
Структурируем импорт
Несмотря на то, что мы можем организовать импорт, используя текущий каталог, переменную окружения PYTHONPATH и даже sys.path , этот процесс часто оказывается неконтролируемым и подверженным ошибкам. Типичный пример даёт нам следующее приложение:
Приложение воссоздаст данную файловую структуру с каталогами и пустыми файлами. Файл structure.py содержит основной скрипт, а files.py — это библиотечный модуль с функциями для работы с файлами. Вот что выводит приложение, запускаемое в данном случае в каталоге structure :
Два файла исходного кода плюс автоматически созданный файл .pyc повторно создаются внутри нового каталога с именем 001 .
Обратимся теперь к исходному коду. Основная функциональность приложения определяется в structure.py :
В строках с 12 по 16 читается корневой путь из командной строки. Точкой здесь обозначается текущий каталог. Этот путь — root файловой иерархии, которую вы воссоздадите.
Вся работа происходит в строках с 19 по 23. Сначала создаётся уникальный путь new_root , который будет корневым каталогом новой файловой иерархии. Затем в цикле проходятся все пути ниже исходного root , и они воссоздаются в виде пустых файлов внутри новой файловой иерархии.
В строке 26 вызывается main() . О проверке условия if в строке 25 подробнее узнаем дальше в статье. А пока нам достаточно знать, что специальная переменная __name__ внутри скриптов имеет значение __main__ , а внутри импортируемых модулей получает имя модуля.
Обратите внимание: в строке 8 импортируются файлы . В этом библиотечном модуле содержатся две служебные функции:
unique_path() работает со счётчиком для обнаружения пути, которого уже не существует. В приложении он нужен, чтобы найти уникальный подкаталог, который будет использоваться в качестве new_root вновь созданной файловой иерархии. add_empty_file() обеспечивает создание всех необходимых каталогов до того, как с помощью .touch() будет создан пустой файл.
Ещё раз взглянем на импорт файлов :
Выглядит он совершенно невинно. Однако по мере роста проекта эта строка станет источником некоторых проблем. Даже если импорт файлов происходит из проекта structure , этот импорт абсолютный: он не начинается с точки. А это означает, что файлы должны быть найдены в пути импорта, чтобы импорт состоялся.
К счастью, каталог с текущим скриптом всегда находится в пути импорта Python. Так что, пока проект не набрал обороты, импорт работает нормально. Но дальше возможны варианты.
Например, кто-то захочет импортировать скрипт в Jupyter Notebook и запускать его оттуда. Или иметь доступ к библиотеке файлов в другом проекте. Могут даже с помощью PyInstaller создавать исполняемые файлы, чтобы упростить их дальнейшее распространение. К сожалению, любой из этих сценариев может вызвать проблемы с импортом файлов.
Каким образом? Вот вам пример. Возьмём руководство по PyInstaller и создадим точку входа в приложение. Добавим дополнительный каталог за пределами каталога приложения:
В этом внешнем каталоге создадим скрипт точки входа cli.py :
Этот скрипт импортирует из исходного скрипта main() и запускает его. Обратите внимание: когда импортируется structure , main() не запускается из-за проверки условия if в строке 25 внутри structure.py . То есть нужно запускать main() явным образом.
По идее, это должно быть аналогично прямому запуску приложения:
Почему же запуск не удался? При импорте файлов неожиданно возникает ошибка.
Проблема в том, что при запуске приложения с cli.py поменялся адрес текущего скрипта, а это, в свою очередь, меняет путь импорта. Файлы больше не находятся в пути импорта, поэтому их абсолютный импорт невозможен.
Одно из возможных решений — поменять путь импорта Python. Вот так:
Здесь в пути импорта есть папка со structure.py и files.py . Поэтому это решение работает. Но такой подход неидеален, ведь путь импорта может стать очень неаккуратным и трудным для понимания.
Фактически происходит воссоздание функции ранних версий Python, называемой неявным относительным импортом. Она была удалена из языка в руководстве по стилю PEP 328 со следующим обоснованием:
В Python 2.4 и более ранних версиях при чтении модуля, расположенного внутри пакета, неясно: относится ли import foo к модулю верхнего уровня или к другому модулю внутри пакета. По мере расширения библиотеки Python всё больше и больше имеющихся внутренних модулей пакета вдруг случайно затеняют модули стандартной библиотеки. Внутри пакетов эта проблема усугубляется из-за невозможности указать, какой модуль имеется в виду. (Источник.)
Другое решение — использовать вместо этого относительный импорт. Меняем импорт в structure.py :
Теперь приложение можно запустить через скрипт точки входа:
Но вызвать напрямую приложение больше не получится:
Проблема в том, что относительный импорт разрешается в скриптах иначе, чем импортируемые модули. Конечно, можно вернуться и восстановить абсолютный импорт, а затем выполнить непосредственный запуск скрипта или даже попытаться провернуть акробатический трюк с try. except и реализовать абсолютный или относительный импорт файлов (в зависимости от того, что сработает).
Есть даже официально санкционированный хакерский приём, позволяющий работать с относительным импортом в скриптах. Вот только в большинстве случаев при этом придётся менять sys.path . Цитируя Реймонда Хеттинджера, можно сказать:
И действительно, лучшее (и более стабильное) решение — поэкспериментировать с системой управления пакетами и импорта Python, устанавливая проект в качестве локального пакета с помощью pip .
Создание и установка локального пакета
При установке пакета из PyPI этот пакет становится доступным для всех скриптов в вашей среде. Но пакеты можно установить и с локального компьютера, и они точно так же будут доступны.
Создание локального пакета не приводит к большому расходу вычислительных ресурсов. Сначала создаём минимальный набор файлов setup.cfg и setup.py во внешнем каталоге structure :
Теоретически name и version могут быть любыми. Надо лишь учесть, что они задействованы pip при обращении к пакету, поэтому стоит выбрать для него значения, легко узнаваемые и выделяющие его из массы других пакетов.
Рекомендуется давать всем таким локальным пакетам общий префикс, например local_ или ваше имя пользователя. В пакетах должен находиться каталог или каталоги, содержащие исходный код. Теперь можно установить пакет локально с помощью pip :
Эта команда установит пакет в вашу систему. structure после этого будет находиться в пути импорта Python. То есть можно будет выполнить её в любом месте, не беспокоясь о каталоге скрипта, относительном импорте или других сложностях. -e означает editable (редактируемый). Это важная опция, позволяющая менять исходный код пакета без его переустановки.
Примечание: такой установочный файл отлично подходит для самостоятельной работы с проектами. Если же вы планируете поделиться кодом ещё с кем-то, то стоит добавить в установочный файл кое-какую дополнительную информацию.
Теперь, когда structure в системе установлена, можно использовать следующую инструкцию импорта:
Она будет работать независимо от того, чем закончится вызов приложения.
Совет: старайтесь разделять в коде скрипты и библиотеки. Вот хорошее практическое правило:
- Скрипт предназначен для запуска.
- Библиотека предназначена для импорта.
Возможно, у вас есть код, который вы хотите запускать самостоятельно и импортировать из других скриптов. На этот случай стоит провести рефакторинг кода, чтобы разделить общую часть на библиотечный модуль.
Разделять скрипты и библиотеки — неплохая идея, тем не менее в Python все файлы можно запускать и импортировать. Ближе к завершению статьи подробнее расскажем о том, как создавать модули, которые хорошо справляются и с тем, и с другим.
Пакеты пространства имён
Модули и пакеты в Python очень тесно связаны с файлами и каталогами. Это отличает Python от многих других языков программирования, в которых пакеты — это не более чем пространства имён без обязательной привязки к тому, как организован исходный код. Для примера можете ознакомиться с обсуждением на PEP 402.
Пакеты пространства имён доступны в Python с версии 3.3. Они в меньшей степени зависят от имеющейся здесь файловой иерархии. Так, пакеты пространств имён могут быть разделены на несколько каталогов. Пакет пространства имён создаётся автоматически, если у вас есть каталог, содержащий файл .py , но нет __init__.py . Подробное объяснение смотрите в PEP 420.
Замечание: справедливости ради стоит отметить, что пакеты неявных пространств имён появились в Python 3.3. В более ранних версиях Python пакеты пространств имён можно было создавать вручную несколькими различными несовместимыми способами. Все эти ранние подходы обобщены и в упрощённом виде представлены в PEP 420.
Для лучшего понимания пакетов пространства имён попробуем реализовать один из них. В качестве поясняющего примера рассмотрим такую задачу. Дано: объект Song . Требуется преобразовать его в одно из строковых представлений. То есть нужно сериализовать объекты Song .
А конкретнее — нужно реализовать код, который работает примерно так:
Предположим, нам повезло наткнуться на стороннюю реализацию нескольких форматов, в которые нужно сериализовать объекты, и она организована как пакет пространства имён:
В файле json.py содержится код, который может сериализовать объект в формат JSON:
Этого несколько ограниченного интерфейса сериализатора будет достаточно, чтобы продемонстрировать, как работают пакеты пространства имён.
В файле xml.py содержится аналогичный XmlSerializer , который может преобразовать объект в XML:
Обратите внимание, что оба этих класса реализуют один и тот же интерфейс с помощью методов .start_object() , .add_property() и .__str__() .
Затем создаём класс Song , который может применять эти сериализаторы:
Song (песня) определяется по идентификатору, названию и исполнителю. Обратите внимание, что .serialize() не нужно знать, в какой формат происходит преобразование, потому что он использует общий интерфейс, определённый ранее.
Установив пакет сторонних serializers , можно работать с ним так:
Для разных объектов сериализатора, вызывая .serialize() получаем разные представления песни.
Примечание: при запуске кода можно получить ModuleNotFoundError или ImportError . Всё потому, что serializers нет в пути импорта Python. Но скоро мы увидим, как решить эту проблему.
Пока все идёт хорошо. Но теперь песни нужно преобразовать и в представление YAML, которое не поддерживается сторонней библиотекой. Тут-то в дело и вступают пакеты пространства имён: можем добавить в пакет serializers собственный YamlSerializer , не прибегая к сторонней библиотеке.
Сначала создаём каталог в локальной файловой системе под названием serializers . Важно, чтобы имя каталога совпадало с именем настраиваемого пакета пространства имён:
В файле yaml.py определяем собственный YamlSerializer . Делаем это с помощью пакета PyYAML , который должен быть установлен из PyPI:
Форматы YAML и JSON очень похожи, поэтому здесь можно повторно использовать большую часть реализации JsonSerializer :
Смотрите: YamlSerializer здесь основан на JsonSerializer , который импортируется из этих самых serializers . А раз json и yaml являются частью одного и того же пакета пространства имён, то мы можем даже использовать относительный импорт: from .json import JsonSerializer .
Поэтому, продолжая этот пример, мы теперь можем преобразовать песню в YAML:
Подобно обычным модулям и пакетам, пакеты пространства имён должны находиться в пути импорта Python. Если бы мы делали, как в предыдущих примерах, то могли бы столкнуться с проблемами: Python не находил бы serializers . В реальном коде мы бы использовали pip для установки сторонней библиотеки, так что они автоматически оказывались бы в нашем пути.
Примечание: в исходном примере выбор сериализатора делался более динамично. Позже мы увидим, как использовать пакеты пространств имён в соответствующем шаблоне «фабричный метод».
И нужно позаботиться о том, чтобы локальная библиотека была доступна так же, как и обычный пакет. Как мы уже убедились, это можно сделать либо запустив Python из соответствующего каталога, либо опять-таки используя pip для установки локальной библиотеки.
В этом примере мы тестируем, как можно интегрировать фейковый сторонний пакет с нашим локальным пакетом. Будь сторонний third_party реальным пакетом, то мы бы загрузили его из PyPI с помощью pip . А так мы можем сымитировать его, установив third_party локально, как уже было сделано ранее в примере со structure .
Или же можно поколдовать с путём импорта. Поместите каталоги third_party и local в одну папку, а затем настройте путь Python вот так:
Теперь можно использовать все сериализаторы, не беспокоясь о том, где они определены: в стороннем пакете или локально.
Руководство по стилю импорта
В руководстве по стилю Python PEP 8 есть ряд рекомендаций, касающихся импорта. Как всегда, в Python важное значение придаётся читаемости и лёгкости сопровождения кода. Вот несколько общих практических правил относительно того, какого стиля надо придерживаться при оформлении импорта:
- Находится в верхней части файла.
- Прописывается в отдельных строках.
- Организуется в группы: сначала идут импорты стандартной библиотеки, затем сторонние импорты, а после — импорты локальных приложений или библиотек.
- Внутри каждой группы импорты располагаются в алфавитном порядке.
- Предпочтение отдаётся абсолютному импорту над относительным.
- Импорты со спецсимволами типа звёздочки ( from module import * ) стараются не использовать.
Инструменты isort и reorder-python-imports отлично подходят для реализации этих рекомендаций в последовательном стиле импорта. Вот пример раздела импорта внутри пакета Real Python feed reader package:
Обратите внимание на чёткую организацию по группам. Сразу позволяет обозначить зависимости этого модуля, которые должны быть установлены: feedparser и html2text . Обычно подразумевается, что стандартная библиотека доступна. Разделение импортов внутри пакета даёт некоторое представление о внутренних зависимостях кода.
Бывают случаи, когда имеет смысл немного отойти от этих правил. Мы уже видели, что относительный импорт может быть альтернативой при организации иерархии пакетов. В конце статьи мы увидим, как в некоторых случаях можно переместить импорт в определение функции, чтобы прервать циклы импорта.
Импорт в Python. Ресурсы и динамический импорт
Иногда наш код зависит от файлов данных или других ресурсов. В небольших скриптах это не проблема — мы можем указать путь к файлу данных и продолжить работу!
Однако, если файл ресурсов важен для нашего пакета и хочется поделиться им с другими пользователями, возникает несколько проблем:
- У нас не будет контроля над путём к ресурсу, так как это будет зависеть от настроек пользователя, а также от того, как пакет распространяется и устанавливается. Можно попробовать узнать путь к ресурсу с помощью атрибутов пакета __file__ или __path__ , но такой способ не всегда может сработать так, как мы ожидаем.
- Пакет может находиться внутри ZIP-файла или старого файла .eggfile, и в этом случае ресурс даже не будет физическим файлом в компьютере пользователя.
Было предпринято несколько попыток решить эти проблемы, в том числе с помощью setuptools.pkg_resources . Однако с появлением в стандартной библиотеке Python 3.7 importlib.resources теперь есть один стандартный способ работы с ресурсными файлами.
Представляем importlib.resources
importlib.resources предоставляет доступ к ресурсам внутри пакетов. В этом контексте ресурс — это любой файл, находящийся в импортируемом пакете. Файл может соответствовать, а может и не соответствовать физическому файлу в файловой системе.
Здесь есть несколько преимуществ: при повторном использовании системы импорта получаем более последовательный способ работы с файлами внутри пакетов плюс более лёгкий доступ к ресурсным файлам в других пакетах. Вот что об этом сказано в документации:
Если вы можете импортировать пакет, то можете иметь доступ к ресурсам внутри этого пакета. (Источник.)
importlib.resources стали частью стандартной библиотеки в Python 3.7. А для более старых версий Python имеется бэкпорт importlib_resources . Чтобы задействовать бэкпорт, надо установить его из PyPI:
Бэкпорт совместим с Python 2.7, а также Python 3.4 и более поздними версиями.
При работе с importlib.resources есть одно условие: ресурсные файлы должны быть доступны внутри обычного пакета. Пакеты пространства имён не поддерживаются. На практике это означает, что файл должен находиться в каталоге, содержащем файл __init__.py .
В качестве первого примера предположим, что у нас в пакете есть такие ресурсы:
__init__.py — это просто пустой файл, необходимый для указания на то, что books (книги) — это обычный пакет.
Затем можем использовать open_text() и open_binary() для открытия текстовых и бинарных файлов соответственно:
open_text() и open_binary() эквивалентны встроенному open() с параметром mode , имеющим значения rt и rb соответственно. Также доступны в виде read_text() и read_binary() удобные функции для чтения текстовых или двоичных файлов. Ещё больше узнать можно в официальной документации.
Примечание: чтобы полностью перейти на бэкпорт для старых версий Python, импортируем importlib.resources :
Больше узнать об этом можно в разделе «Полезные советы» этой статьи. Далее в этой части статьи покажем несколько сложных примеров работы с ресурсными файлами на практике.
Файлы данных
В качестве более полного примера работы с файлами данных рассмотрим, как можно реализовать программу викторины, основанную на демографических данных Организации Объединенных Наций. Сначала создаём пакет data и загружаем WPP2019_TotalPopulationBySex.csv с веб-сайта ООН:
Откроем файл CSV и посмотрим на данные:
В каждой строке мы видим данные о населении страны за определённый год и вариант, указывающий на соответствующий прогнозный сценарий. В файле содержатся прогнозы численности населения по странам мира до 2100 года.
Следующая функция считывает этот файл и выдаёт общую численность населения той или иной страны за конкретный year (год) и variant (вариант):
Выделенные жирным шрифтом строки показывают применение importlib.resources для открытия файла данных. Функция возвращает словарь с численностью населения:
Имея такой словарь с данными по численности населения, можно сделать много чего интересного, например анализ и визуализации. Ну а мы создадим игру-викторину, в которой участников просят определить, какая страна в наборе имеет самую большую численность населения. Вот как будет выглядеть эта игра:
Вдаваться в подробности этой реализации не будем, так как они совершенно не имеют отношения к предмету рассмотрения нашей статьи. Однако полный исходный код мы можем показать.
Исходный код демографической викторины:
Демографическая викторина состоит из двух функций: одна считывает данные по численности населения (как мы это делали чуть выше), а другая запускает саму викторину:
Обратите внимание: здесь в строке 24 мы проверяем, что LocID меньше 900 . LocID , равный 900 и выше, указывает не на страновые данные, а на данные по миру, частям света, такие как World , Asia и т.д.
Пример: значки и Tkinter
При создании графических пользовательских интерфейсов (ГПИ) часто требуется включать ресурсные файлы, такие как значки. На следующем примере научимся делать это с помощью importlib.resources . В итоге приложение будет выглядеть довольно просто, но со вкусом благодаря оригинальному значку и оформлению кнопки Goodbye:
В примере используется пакет ГПИ Tkinter, доступный в стандартной библиотеке. Он основан на оконной системе Tk, изначально разработанной для языка программирования Tcl. Существует множество других пакетов ГПИ, доступных для Python. Если вы используете один из них, то должны уметь добавлять значки в своё приложение с помощью идей, подобных тем, что представлены здесь.
В Tkinter изображения обрабатываются классом PhotoImage . Чтобы создать PhotoImage , передаём путь к файлу изображения.
При распространении пакета вовсе не гарантируется, что ресурсные файлы будут существовать в файловой системе как физические файлы. importlib.resources решает эту проблему с помощью path() . Эта функция вернёт путь к ресурсному файлу, создав при необходимости временный файл.
Чтобы убедиться, что все временные файлы очищены правильно, задействуем path() в качестве менеджера контекста, используя ключевое слово with :
Для полного примера предположим, что у нас есть следующая файловая иерархия:
Хотите попробовать пример самостоятельно? Скачайте эти файлы вместе с остальным исходным кодом, приведённым в этой статье, перейдя по ссылке ниже:
Получить исходный код: Нажмите здесь и получите исходный код, используемый для изучения системы импорта Python в этой статье.
Код хранится в файле со специальным именем __main__.py . Это имя указывает на то, файл является точкой входа для пакета. Благодаря файлу __main__.py наш пакет может выполняться с python -m :
ГПИ определяется в классе Hello . Обратите внимание, что для получения пути к файлам изображений используется importlib.resources :
Официальная документация содержит хороший список ресурсов, с которого можно начать изучение. Ещё один отличный ресурс — это «Руководство по TkDocs», которое показывает, как использовать Tk в других языках.
Примечание: единственное, что может вызывать неудобство при работе с изображениями в Tkinter, так это то, что здесь нужно следить за тем, чтобы изображения не удалялись механизмом автоматического управления памятью. Из-за того, как Python и Tk взаимодействуют, сборщик мусора в Python (по крайней мере, в CPython) не регистрирует, что .iconphoto() и Button используют изображения.
Чтобы убедиться, что изображения сохраняются, нужно вручную добавлять ссылку на них. В нашем коде это было сделано в строках 18 и 31.
Динамический импорт
Одна из отличительных особенностей Python в том, что это очень динамичный язык. Можно много чего сделать с программой Python во время её выполнения (хотя иногда делать этого не стоит), например добавлять атрибуты к классу, переопределять методы или изменять строку документации модуля. Мы можем изменить print() так, чтобы он ничего не делал:
На самом деле, мы не переопределяем print() . Мы определяем другой print() , который затеняет встроенный print() . Для возвращения к исходному print() удаляем наш пользовательский print() с помощью del print . Так можно затенить любой объект Python, встроенный в интерпретатор.
Обратите внимание: в приведенном выше примере мы переопределяем print() с помощью лямбда-функции. Также можно было бы использовать определение обычной функции:
В этой части статьи мы ещё узнаем, как выполнять динамический импорт в Python. Освоив его, вы избавитесь от необходимости решать, что импортировать во время выполнения программы.
importlib
До сих пор мы использовали ключевое слово import для явного импорта модулей и пакетов в Python. Однако весь механизм импорта доступен в пакете importlib , что позволяет нам выполнять импорт более динамично. Следующий скрипт запрашивает у пользователя имя модуля, импортирует этот модуль и выводит строку его документации:
import_module() возвращает объект модуля, который можно привязать к любой переменной. После чего мы можем обращаться с этой переменной как с обычным импортируемым модулем. Этот скрипт можно использовать вот так:
В каждом случае модуль импортируется динамически с помощью import_module() .
Фабричный метод с пакетами пространства имён
Вернёмся к примеру с сериализаторами. Благодаря serializers , реализованным в качестве пакета пространства имён, у нас появилась возможность добавлять пользовательские сериализаторы. Сериализаторы создаются с помощью фабрики сериализаторов. Попробуем сделать это, использовав importlib .
Добавим в наш локальный пакет пространства имён serializers следующий код:
Фабрика get_serializer() может создать сериализаторы динамически на основе параметра format , а затем serialize() может применить сериализатор к любому объекту, реализующему метод .serialize() .
Фабрика делает строгие предположения об именовании модуля и класса, которые содержат конкретные сериализаторы. Далее в статье мы узнаем об архитектуре плагинов, которая придаёт больше гибкости.
А пока воссоздадим предыдущий пример вот таким образом:
В этом случае нам больше не нужно выполнять явный импорт каждого сериализатора. Имя сериализатора указываем со строкой. Строка может быть даже выбрана пользователем во время выполнения.
Обратите внимание: в обычном пакете мы бы, наверное, реализовали get_serializer() и serialize() в файле __init__.py . Так мы могли бы просто импортировать serializers , а затем вызвать serializers.serialize() .
Но пакеты пространства имён не могут использовать __init__.py , поэтому нужно реализовать эти функции в отдельном модуле.
Последний пример показывает, что мы получаем соответствующее сообщение об ошибке, если пытаемся сериализоваться в формат, который не был реализован.
Пакет плагинов
Рассмотрим ещё один пример использования динамического импорта. Мы можем использовать следующий модуль для настройки гибкой архитектуры плагинов в коде. Это похоже на то, что было в предыдущем примере, в котором мы могли подключить сериализаторы для различных форматов, добавив новые модули.
Эскпериментальное средство визуализации Glue — это одно из приложений, эффективно использующих плагины. Оно сходу может читать множество различных форматов данных. Если всё-таки нужный формат данных не поддерживается, можно написать собственный пользовательский загрузчик данных.
Просто добавляется функция, которая декорируется и помещается в специальное место, чтобы Glue было легче её найти. И никакую часть исходного кода Glue менять не надо. Все детали смотрите в документации.
Мы можем настроить аналогичную архитектуру плагина для использования в своих проектах. В этой архитектуре два уровня:
- Пакет плагинов — это набор связанных плагинов, соответствующих пакету Python.
- Плагин — это пользовательское поведение, доступное в модуле Python.
Модуль plugins , который предоставляет архитектуру плагина, имеет следующие функции:
Фабричные функции используются для удобного добавления функциональности в пакеты плагинов. Вскоре увидим примеры того, как это происходит.
Рассматривать код во всех деталях не будем: это выходит за рамки статьи. Если вам интересно, можем показать реализацию ниже.
В следующем коде показана реализация plugins.py , описанная выше:
Эта реализация немного упрощена. Так, она не выполняет явной обработки ошибок. Более полная реализация доступна по ссылке на проект PyPlugs.
_import() использует importlib.import_module() для динамической загрузки плагинов. А _import_all() использует importlib.resources.contents() для перечисления всех доступных плагинов в данном пакете.
Рассмотрим несколько примеров использования плагинов. Первый пример — это пакет greeter , который можно использовать для добавления различных приветствий в приложение. Полная архитектура плагинов здесь определённо избыточна, но она показывает, как работают плагины. Представьте, что у вас такой пакет greeter :
Каждый модуль greeter определяет функцию, которая принимает один аргумент name . Посмотрите, как с помощью декоратора @register все они регистрируются в качестве плагинов:
Обратите внимание: для упрощения обнаружения и импорта плагинов имя каждого плагина содержит не имя функции, а имя модуля, в котором он находится. Поэтому на каждый файл может быть только один плагин.
В завершение настройки greeter как пакета плагинов можно использовать фабричные функции в plugins для добавления функциональности в сам пакет greeter :
Теперь мы можем использовать greetings() и greet() вот так:
Заметьте, что greetings() автоматически обнаруживает все плагины, доступные в пакете.
Мы также можем более динамически выбирать, какой плагин вызывать. В следующем примере выбираем плагин случайным образом. Плагин также можно выбрать на основе конфигурационного файла или пользовательских данных:
Для обнаружения и вызова различных плагинов их нужно импортировать. Остановимся ненадолго на том, как plugins работают с импортом. Всё самое главное происходит в следующих двух функциях внутри plugins.py :
_import() внешне кажется простым. Для импорта модуля он использует importlib . Но здесь происходит ещё кое-что:
- Система импорта Python гарантирует, что каждый плагин импортируется только один раз.
- Декораторы @register , определённые внутри каждого модуля plugin, регистрируют каждый импортированный плагин.
- В полной реализации для работы с отсутствующими плагинами будет обработка ошибок.
_import_all() обнаруживает все плагины в пакете. Вот как это работает:
- contents() из importlib.resources выводит список всех файлов внутри пакета.
- Результаты фильтруются для поиска потенциальных плагинов.
- Каждый файл Python, не начинающийся с подчеркивания, импортируется.
- Плагины в любом из файлов обнаруживаются и регистрируются.
Завершим эту часть статьи финальной версией пакета пространства имён. Одной из нерешённых проблем было то, что фабрика get_serializer() делала строгие предположения об именовании классов сериализатора. С помощью плагинов можно сделать их более гибкими.
Первым делом добавляем строку, регистрирующую каждый из сериализаторов. Вот пример того, как это делается в сериализаторе yaml :
Затем обновляем get_serializers() для использования plugins :
Мы реализуем get_serializer() с помощью call_factory() , так как это автоматически инстанцирует каждый сериализатор. При таком рефакторинге сериализаторы работают точно так же, как и раньше. Но теперь у нас больше гибкости в именовании классов сериализаторов.
Ещё больше об использовании плагинов можно узнать в PyPlugs на PyPI и презентации Плагины: добавление гибкости приложениям из PyCon 2019.
User Guide#
pip is a command line program. When you install pip, a pip command is added to your system, which can be run from the command prompt as follows:
python -m pip executes pip using the Python interpreter you specified as python. So /usr/bin/python3.7 -m pip means you are executing pip for your interpreter located at /usr/bin/python3.7 .
py -m pip executes pip using the latest Python interpreter you have installed. For more details, read the Python Windows launcher docs.
Installing Packages#
pip supports installing from PyPI, version control, local projects, and directly from distribution files.
The most common scenario is to install from PyPI using Requirement Specifiers
For more information and examples, see the pip install reference.
Basic Authentication Credentials
This is now covered in Authentication .
This is now covered in Authentication .
This is now covered in Authentication .
Using a Proxy Server#
When installing packages from PyPI, pip requires internet access, which in many corporate environments requires an outbound HTTP proxy server.
pip can be configured to connect through a proxy server in various ways:
using the —proxy command-line option to specify a proxy in the form scheme://[user:passwd@]proxy.server:port
by setting the standard environment-variables http_proxy , https_proxy and no_proxy .
using the environment variable PIP_USER_AGENT_USER_DATA to include a JSON-encoded string in the user-agent variable used in pip’s requests.
Requirements Files#
“Requirements files” are files containing a list of items to be installed using pip install like so:
Details on the format of the files are here: Requirements File Format .
Logically, a Requirements file is just a list of pip install arguments placed in a file. Note that you should not rely on the items in the file being installed by pip in any particular order.
In practice, there are 4 common uses of Requirements files:
Requirements files are used to hold the result from pip freeze for the purpose of achieving Repeatable Installs . In this case, your requirement file contains a pinned version of everything that was installed when pip freeze was run.
Requirements files are used to force pip to properly resolve dependencies. pip 20.2 and earlier doesn’t have true dependency resolution, but instead simply uses the first specification it finds for a project. E.g. if pkg1 requires pkg3>=1.0 and pkg2 requires pkg3>=1.0,<=2.0 , and if pkg1 is resolved first, pip will only use pkg3>=1.0 , and could easily end up installing a version of pkg3 that conflicts with the needs of pkg2 . To solve this problem, you can place pkg3>=1.0,<=2.0 (i.e. the correct specification) into your requirements file directly along with the other top level requirements. Like so:
Requirements files are used to force pip to install an alternate version of a sub-dependency. For example, suppose ProjectA in your requirements file requires ProjectB , but the latest version (v1.3) has a bug, you can force pip to accept earlier versions like so:
Requirements files are used to override a dependency with a local patch that lives in version control. For example, suppose a dependency SomeDependency from PyPI has a bug, and you can’t wait for an upstream fix. You could clone/copy the src, make the fix, and place it in VCS with the tag sometag . You’d reference it in your requirements file with a line like so:
If SomeDependency was previously a top-level requirement in your requirements file, then replace that line with the new line. If SomeDependency is a sub-dependency, then add the new line.
It’s important to be clear that pip determines package dependencies using install_requires metadata, not by discovering requirements.txt files embedded in projects.
Constraints Files#
Constraints files are requirements files that only control which version of a requirement is installed, not whether it is installed or not. Their syntax and contents is a subset of Requirements Files , with several kinds of syntax not allowed: constraints must have a name, they cannot be editable, and they cannot specify extras. In terms of semantics, there is one key difference: Including a package in a constraints file does not trigger installation of the package.
Use a constraints file like so:
Constraints files are used for exactly the same reason as requirements files when you don’t know exactly what things you want to install. For instance, say that the “helloworld” package doesn’t work in your environment, so you have a local patched version. Some things you install depend on “helloworld”, and some don’t.
One way to ensure that the patched version is used consistently is to manually audit the dependencies of everything you install, and if “helloworld” is present, write a requirements file to use when installing that thing.
Constraints files offer a better way: write a single constraints file for your organisation and use that everywhere. If the thing being installed requires “helloworld” to be installed, your fixed version specified in your constraints file will be used.
Constraints file support was added in pip 7.1. In Changes to the pip dependency resolver in 20.3 (2020) we did a fairly comprehensive overhaul, removing several undocumented and unsupported quirks from the previous implementation, and stripped constraints files down to being purely a way to specify global (version) limits for packages.
Installing from Wheels#
“Wheel” is a built, archive format that can greatly speed installation compared to building and installing from source archives. For more information, see the Wheel docs , PEP 427, and PEP 425.
pip prefers Wheels where they are available. To disable this, use the —no-binary flag for pip install .
If no satisfactory wheels are found, pip will default to finding source archives.
To install directly from a wheel archive:
To include optional dependencies provided in the provides_extras metadata in the wheel, you must add quotes around the install target name:
In the future, the path[extras] syntax may become deprecated. It is recommended to use PEP 508 syntax wherever possible.
For the cases where wheels are not available, pip offers pip wheel as a convenience, to build wheels for all your requirements and dependencies.
pip wheel requires the wheel package to be installed, which provides the “bdist_wheel” setuptools extension that it uses.
To build wheels for your requirements and all their dependencies to a local directory:
And then to install those requirements just using your local directory of wheels (and not from PyPI):
Uninstalling Packages#
pip is able to uninstall most packages like so:
pip also performs an automatic uninstall of an old version of a package before upgrading to a newer version.
For more information and examples, see the pip uninstall reference.
Listing Packages#
To list installed packages:
To list outdated packages, and show the latest version available:
To show details about an installed package:
For more information and examples, see the pip list and pip show reference pages.
Searching for Packages#
pip can search PyPI for packages using the pip search command:
The query will be used to search the names and summaries of all packages.
For more information and examples, see the pip search reference.
This is now covered in Configuration .
This is now covered in Configuration .
This is now covered in Configuration .
This is now covered in Configuration .
Command Completion#
pip comes with support for command line completion in bash, zsh and fish.
To setup for bash:
To setup for zsh:
To setup for fish:
To setup for powershell:
Alternatively, you can use the result of the completion command directly with the eval function of your shell, e.g. by adding the following to your startup file:
Installing from local packages#
In some cases, you may want to install from local packages only, with no traffic to PyPI.
First, download the archives that fulfill your requirements:
Note that pip download will look in your wheel cache first, before trying to download from PyPI. If you’ve never installed your requirements before, you won’t have a wheel cache for those items. In that case, if some of your requirements don’t come as wheels from PyPI, and you want wheels, then run this instead:
Then, to install from local only, you’ll be using —find-links and —no-index like so:
“Only if needed” Recursive Upgrade#
pip install —upgrade now has a —upgrade-strategy option which controls how pip handles upgrading of dependencies. There are 2 upgrade strategies supported:
eager : upgrades all dependencies regardless of whether they still satisfy the new parent requirements
only-if-needed : upgrades a dependency only if it does not satisfy the new parent requirements
The default strategy is only-if-needed . This was changed in pip 10.0 due to the breaking nature of eager when upgrading conflicting dependencies.
It is important to note that —upgrade affects direct requirements (e.g. those specified on the command-line or via a requirements file) while —upgrade-strategy affects indirect requirements (dependencies of direct requirements).
As an example, say SomePackage has a dependency, SomeDependency , and both of them are already installed but are not the latest available versions:
pip install SomePackage : will not upgrade the existing SomePackage or SomeDependency .
pip install —upgrade SomePackage : will upgrade SomePackage , but not SomeDependency (unless a minimum requirement is not met).
pip install —upgrade SomePackage —upgrade-strategy=eager : upgrades both SomePackage and SomeDependency .
As an historic note, an earlier “fix” for getting the only-if-needed behaviour was:
A proposal for an upgrade-all command is being considered as a safer alternative to the behaviour of eager upgrading.
User Installs#
With Python 2.6 came the “user scheme” for installation, which means that all Python distributions support an alternative install location that is specific to a user. The default location for each OS is explained in the python documentation for the site.USER_BASE variable. This mode of installation can be turned on by specifying the —user option to pip install .
Moreover, the “user scheme” can be customized by setting the PYTHONUSERBASE environment variable, which updates the value of site.USER_BASE .
To install “SomePackage” into an environment with site.USER_BASE customized to ‘/myappenv’, do the following:
pip install —user follows four rules:
When globally installed packages are on the python path, and they conflict with the installation requirements, they are ignored, and not uninstalled.
When globally installed packages are on the python path, and they satisfy the installation requirements, pip does nothing, and reports that requirement is satisfied (similar to how global packages can satisfy requirements when installing packages in a —system-site-packages virtualenv).
pip will not perform a —user install in a —no-site-packages virtualenv (i.e. the default kind of virtualenv), due to the user site not being on the python path. The installation would be pointless.
In a —system-site-packages virtualenv, pip will not install a package that conflicts with a package in the virtualenv site-packages. The —user installation would lack sys.path precedence and be pointless.
To make the rules clearer, here are some examples:
From within a —no-site-packages virtualenv (i.e. the default kind):
From within a —system-site-packages virtualenv where SomePackage==0.3 is already installed in the virtualenv:
From within a real python, where SomePackage is not installed globally:
From within a real python, where SomePackage is installed globally, but is not the latest version:
From within a real python, where SomePackage is installed globally, and is the latest version:
This is now covered in Repeatable Installs .
Fixing conflicting dependencies
Using pip from your program#
As noted previously, pip is a command line program. While it is implemented in Python, and so is available from your Python code via import pip , you must not use pip’s internal APIs in this way. There are a number of reasons for this:
The pip code assumes that it is in sole control of the global state of the program. pip manages things like the logging system configuration, or the values of the standard IO streams, without considering the possibility that user code might be affected.
pip’s code is not thread safe. If you were to run pip in a thread, there is no guarantee that either your code or pip’s would work as you expect.
pip assumes that once it has finished its work, the process will terminate. It doesn’t need to handle the possibility that other code will continue to run after that point, so (for example) calling pip twice in the same process is likely to have issues.
This does not mean that the pip developers are opposed in principle to the idea that pip could be used as a library — it’s just that this isn’t how it was written, and it would be a lot of work to redesign the internals for use as a library, handling all of the above issues, and designing a usable, robust and stable API that we could guarantee would remain available across multiple releases of pip. And we simply don’t currently have the resources to even consider such a task.
What this means in practice is that everything inside of pip is considered an implementation detail. Even the fact that the import name is pip is subject to change without notice. While we do try not to break things as much as possible, all the internal APIs can change at any time, for any reason. It also means that we generally won’t fix issues that are a result of using pip in an unsupported way.
It should also be noted that installing packages into sys.path in a running Python process is something that should only be done with care. The import system caches certain data, and installing new packages while a program is running may not always behave as expected. In practice, there is rarely an issue, but it is something to be aware of.
Having said all of the above, it is worth covering the options available if you decide that you do want to run pip from within your program. The most reliable approach, and the one that is fully supported, is to run pip in a subprocess. This is easily done using the standard subprocess module:
If you want to process the output further, use one of the other APIs in the module. We are using freeze here which outputs installed packages in requirements format.:
If you don’t want to use pip’s command line functionality, but are rather trying to implement code that works with Python packages, their metadata, or PyPI, then you should consider other, supported, packages that offer this type of ability. Some examples that you could consider include:
packaging — Utilities to work with standard package metadata (versions, requirements, etc.)
setuptools (specifically pkg_resources ) — Functions for querying what packages the user has installed on their system.
distlib — Packaging and distribution utilities (including functions for interacting with PyPI).
Changes to the pip dependency resolver in 20.3 (2020)#
pip 20.3 has a new dependency resolver, on by default for Python 3 users. (pip 20.1 and 20.2 included pre-release versions of the new dependency resolver, hidden behind optional user flags.) Read below for a migration guide, how to invoke the legacy resolver, and the deprecation timeline. We also made a two-minute video explanation you can watch.
We will continue to improve the pip dependency resolver in response to testers’ feedback. Please give us feedback through the resolver testing survey.
Watch out for#
The big change in this release is to the pip dependency resolver within pip.
Computers need to know the right order to install pieces of software (“to install x , you need to install y first”). So, when Python programmers share software as packages, they have to precisely describe those installation prerequisites, and pip needs to navigate tricky situations where it’s getting conflicting instructions. This new dependency resolver will make pip better at handling that tricky logic, and make pip easier for you to use and troubleshoot.
The most significant changes to the resolver are:
It will reduce inconsistency: it will no longer install a combination of packages that is mutually inconsistent. In older versions of pip, it is possible for pip to install a package which does not satisfy the declared requirements of another installed package. For example, in pip 20.0, pip install "six<1.12" "virtualenv==20.0.2" does the wrong thing, “successfully” installing six==1.11 , even though virtualenv==20.0.2 requires six>=1.12.0,<2 (defined here). The new resolver, instead, outright rejects installing anything if it gets that input.
It will be stricter — if you ask pip to install two packages with incompatible requirements, it will refuse (rather than installing a broken combination, like it did in previous versions).
So, if you have been using workarounds to force pip to deal with incompatible or inconsistent requirements combinations, now’s a good time to fix the underlying problem in the packages, because pip will be stricter from here on out.
This also means that, when you run a pip install command, pip only considers the packages you are installing in that command, and may break already-installed packages. It will not guarantee that your environment will be consistent all the time. If you pip install x and then pip install y , it’s possible that the version of y you get will be different than it would be if you had run pip install x y in a single command. We are considering changing this behavior (per #7744) and would like your thoughts on what pip’s behavior should be; please answer our survey on upgrades that create conflicts.
We are also changing our support for Constraints Files , editable installs, and related functionality. We did a fairly comprehensive overhaul and stripped constraints files down to being purely a way to specify global (version) limits for packages, and so some combinations that used to be allowed will now cause errors. Specifically:
Constraints don’t override the existing requirements; they simply constrain what versions are visible as input to the resolver (see #9020)
Providing an editable requirement ( -e . ) does not cause pip to ignore version specifiers or constraints (see #8076), and if you have a conflict between a pinned requirement and a local directory then pip will indicate that it cannot find a version satisfying both (see #8307)
Hash-checking mode requires that all requirements are specified as a == match on a version and may not work well in combination with constraints (see #9020 and #8792)
If necessary to satisfy constraints, pip will happily reinstall packages, upgrading or downgrading, without needing any additional command-line options (see #8115 and Options that control the installation process )
Unnamed requirements are not allowed as constraints (see #6628 and #8210)
Links are not allowed as constraints (see #8253)
Constraints cannot have extras (see #6628)
Per our Python 2 Support policy, pip 20.3 users who are using Python 2 will use the legacy resolver by default. Python 2 users should upgrade to Python 3 as soon as possible, since in pip 21.0 in January 2021, pip dropped support for Python 2 altogether.
How to upgrade and migrate#
Install pip 20.3 with python -m pip install —upgrade pip .
Validate your current environment by running pip check . This will report if you have any inconsistencies in your set of installed packages. Having a clean installation will make it much less likely that you will hit issues with the new resolver (and may address hidden problems in your current environment!). If you run pip check and run into stuff you can’t figure out, please ask for help in our issue tracker or chat.
Test the new version of pip.
While we have tried to make sure that pip’s test suite covers as many cases as we can, we are very aware that there are people using pip with many different workflows and build processes, and we will not be able to cover all of those without your help.
If you use pip to install your software, try out the new resolver and let us know if it works for you with pip install . Try:
installing several packages simultaneously
re-creating an environment using a requirements.txt file
using pip install —force-reinstall to check whether it does what you think it should
using constraints files
the “Setups to test with special attention” and “Examples to try” below
If you have a build pipeline that depends on pip installing your dependencies for you, check that the new resolver does what you need.
Run your project’s CI (test suite, build process, etc.) using the new resolver, and let us know of any issues.
If you have encountered resolver issues with pip in the past, check whether the new resolver fixes them, and read Dealing with dependency conflicts . Also, let us know if the new resolver has issues with any workarounds you put in to address the current resolver’s limitations. We’ll need to ensure that people can transition off such workarounds smoothly.
If you develop or support a tool that wraps pip or uses it to deliver part of your functionality, please test your integration with pip 20.3.
Troubleshoot and try these workarounds if necessary.
If pip is taking longer to install packages, read Dependency resolution backtracking for ways to reduce the time pip spends backtracking due to dependency conflicts.
If you don’t want pip to actually resolve dependencies, use the —no-deps option. This is useful when you have a set of package versions that work together in reality, even though their metadata says that they conflict. For guidance on a long-term fix, read Dealing with dependency conflicts .
If you run into resolution errors and need a workaround while you’re fixing their root causes, you can choose the old resolver behavior using the flag —use-deprecated=legacy-resolver . This will work until we release pip 21.0 (see Deprecation timeline ).
Please report bugs through the resolver testing survey.
Setups to test with special attention#
Requirements files with 100+ packages
Installation workflows that involve multiple requirements files
Requirements files that include hashes ( Hash-checking Mode ) or pinned dependencies (perhaps as output from pip-compile within pip-tools )