docs/specifiers.md
This guide explains how to specify versions of packages and Python interpreters in Pipenv, including syntax, best practices, and advanced usage patterns.
Pipenv uses the same version specifier format as pip, following PEP 440 standards. These specifiers allow you to control exactly which versions of packages are installed.
| Specifier | Example | Meaning |
|---|---|---|
== | requests==2.28.1 | Exact version |
>= | requests>=2.20.0 | Minimum version |
<= | requests<=2.30.0 | Maximum version |
> | requests>2.0.0 | Greater than version |
< | requests<3.0.0 | Less than version |
!= | requests!=2.29.0 | Not equal to version |
~= | requests~=2.28.0 | Compatible release (equivalent to >=2.28.0,<2.29.0) |
* | requests==* | Any version (not recommended for production) |
You can combine specifiers to create version ranges:
# Install any version between 2.20.0 and 3.0.0
$ pipenv install "requests>=2.20.0,<3.0.0"
The use of double quotes around the package and version specification (i.e. `"requests>=2.20.0,<3.0.0"`) is highly recommended to avoid issues with shell interpretation, especially on Unix-based systems.
The ~= operator (compatible release) is particularly useful:
# Install version 2.28.* (>=2.28.0,<2.29.0)
$ pipenv install "requests~=2.28.0"
# Install version 2.* (>=2.0.0,<3.0.0)
$ pipenv install "requests~=2.0"
This ensures you get bug fixes (micro version updates) but not potentially breaking changes (major or minor version updates, depending on how you specify it).
While not recommended for production, you can use wildcards:
# Install the latest version
$ pipenv install "requests==*"
# or simply
$ pipenv install requests
By default, Pipenv doesn't install pre-release versions. To include them:
# Command line flag
$ pipenv install --pre "requests>=2.0.0"
# Or in Pipfile
# [pipenv]
# allow_prereleases = true
You can specify which Python version to use when creating a virtual environment:
# Use Python 3
$ pipenv --python 3
# Use Python 3.10 specifically
$ pipenv --python 3.10
# Use a specific Python executable
$ pipenv --python /usr/local/bin/python3.10
This creates a Pipfile with a [requires] section:
[requires]
python_version = "3.10"
You can specify either a Python version or a full version:
# In your Pipfile
[requires]
python_version = "3.10" # Any 3.10.x version
Or for more specific control:
# In your Pipfile
[requires]
python_full_version = "3.10.4" # Exactly Python 3.10.4
**`python_version` only accepts an exact version string**, such as `"3.10"` or `"3"`.
It does **not** accept version range specifiers like `">= 3.6"` or `"~= 3.9"`.
If you write `python_version = ">= 3.6"`, Pipenv will warn that the required Python
version was not found and may behave unexpectedly:
Warning: Python >= 3.6 was not found on your system...
Warning: Your Pipfile requires python_version >= 3.6, but you are using 3.9.2 (...)
To express a minimum Python requirement, simply set the lowest version you support
as the exact `python_version` (e.g. `python_version = "3.9"`). If you need
a fully exact pin, use `python_full_version` instead (e.g. `python_full_version = "3.9.7"`).
When you run pipenv install without specifying a Python version:
[requires] section in the Pipfilepython_full_version is specified, it tries to use that exact versionpython_version is specified, it tries to find a compatible versionYou can install packages directly from version control systems:
# From a Git repository
$ pipenv install -e git+https://github.com/requests/[email protected]#egg=requests
The format follows this pattern:
<vcs_type>+<scheme>://<location>/<user_or_organization>/<repository>@<branch_or_tag>#egg=<package_name>
Where:
<vcs_type> can be git, bzr, svn, or hg<scheme> can be http, https, ssh, or file@<branch_or_tag> is optional and specifies a specific branch, tag, or commitThis will be reflected in your Pipfile:
[packages]
requests = {editable = true, git = "https://github.com/requests/requests.git", ref = "v2.31.0"}
You can install packages from a local path using the path attribute:
# Install a local package in editable mode
$ pipenv install -e ./path/to/package
# Install the current directory as an editable package
$ pipenv install -e .
This will be reflected in your Pipfile:
[packages]
my-package = {editable = true, path = "./path/to/package"}
# or, for the current directory:
my-package = {editable = true, path = "."}
To install a local package without editable mode:
$ pipenv install ./path/to/package
[packages]
my-package = {path = "./path/to/package"}
You can install packages directly from a remote URL (wheel or source distribution)
using the file attribute:
$ pipenv install https://example.com/packages/my-package-1.0.tar.gz
This will be reflected in your Pipfile:
[packages]
my-package = {file = "https://example.com/packages/my-package-1.0.tar.gz"}
pathvsfile: usepathfor local filesystem locations (e.g.,.or./libs/my-package) andfilefor remote HTTP/HTTPS URLs.
You can specify that a package should only be installed on certain platforms using PEP 508 markers:
# Install pywinusb only on Windows
$ pipenv install "pywinusb ; sys_platform == 'win32'"
This will be reflected in your Pipfile:
[packages]
pywinusb = {version = "*", markers = "sys_platform == 'win32'"}
In addition to the full markers syntax, Pipenv supports shorthand keys for common markers directly in Pipfile entries:
[packages]
# These two forms are equivalent:
pywinusb = {version = "*", markers = "sys_platform == 'win32'"}
pywinusb = {version = "*", sys_platform = "== 'win32'"}
# Platform-specific using platform_machine:
special-arm-lib = {version = "*", platform_machine = "== 'arm64'"}
# macOS-only dependency:
pyobjc = {version = "*", sys_platform = "== 'darwin'"}
Any key from the PEP 508 environment markers can be used as a shorthand.
When `pipenv lock` runs, pip resolves **all** packages in your `Pipfile`, regardless of
platform markers. If a package with a `sys_platform == 'win32'` marker is listed and
pip cannot find a matching distribution for it on your current platform (e.g. Linux),
you may see an error like:
ERROR: No matching distribution found for pywin32
This happens because pip's resolver attempts to download metadata for all listed packages
and some Windows-only packages do not publish distributions for Linux/macOS.
**Workaround:** Ensure the package supports all platforms at the *metadata* level, or
split Windows-specific packages into a separate Pipfile or category. For packages that
truly have no Linux/macOS releases at all, consider managing them outside of Pipenv for
the non-Windows environments.
Use the platform_machine marker to target specific CPU architectures:
[packages]
# Only install on ARM64 (e.g., Apple Silicon Macs, ARM Linux)
arm-optimized = {version = "*", platform_machine = "== 'arm64'"}
# Only install on x86_64 systems
x86-optimized = {version = "*", platform_machine = "== 'x86_64'"}
# macOS on Apple Silicon only
macos-arm = {version = "*", markers = "sys_platform == 'darwin' and platform_machine == 'arm64'"}
Common platform_machine values:
x86_64 — 64-bit Intel/AMD (Linux, macOS)arm64 — ARM 64-bit (Apple Silicon macOS)aarch64 — ARM 64-bit (Linux)AMD64 — 64-bit Intel/AMD (Windows)Note:
platform_machinecontrols whether a package is installed based on the current machine's architecture. It does not control which wheel variant pip selects (e.g., it cannot force pip to choose auniversal2wheel over anarm64wheel). To install a specific wheel file, use thefileorpathattribute instead — see Local and Remote File Dependencies.
You can specify dependencies that are only needed for certain Python versions:
[packages]
typing = {version = ">=3.6.2", markers = "python_version < '3.5'"}
dataclasses = {version = ">=0.8", markers = "python_version < '3.7'"}
You can use complex logical expressions in markers:
[packages]
unittest2 = {version = ">=1.0,<3.0", markers = "python_version < '2.7.9' or (python_version >= '3.0' and python_version < '3.4')"}
Common markers include:
python_version: Python version in 'X.Y' formatpython_full_version: Python version in 'X.Y.Z' formatsys_platform: Platform name (e.g., 'win32', 'linux', 'darwin')platform_machine: Machine type (e.g., 'x86_64', 'arm64', 'aarch64', 'AMD64')platform_system: Operating system name (e.g., 'Linux', 'Darwin', 'Windows')platform_python_implementation: Python implementation (e.g., 'CPython', 'PyPy')os_name: Name of the operating system (e.g., 'posix', 'nt')Many packages provide optional features as "extras":
# Install requests with the 'security' and 'socks' extras
$ pipenv install "requests[security,socks]"
This will be reflected in your Pipfile:
[packages]
requests = {version = "*", extras = ["security", "socks"]}
Pipenv supports organizing dependencies into different categories beyond the standard packages and dev-packages.
In your Pipfile:
[packages]
requests = "*"
[dev-packages]
pytest = "*"
[docs]
sphinx = "*"
sphinx-rtd-theme = "*"
[tests]
pytest-cov = "*"
# Install a package in a specific category
$ pipenv install sphinx --categories="docs"
# Install all packages from specific categories
$ pipenv install --categories="docs,tests"
# Lock only specific categories
$ pipenv lock --categories="docs,tests"
For applications, use specific versions to ensure stability:
[packages]
# Exact version for critical dependencies
requests = "==2.28.1"
# Compatible release for less critical dependencies
flask = "~=2.0.1"
# Version range for flexible dependencies
urllib3 = ">=1.26.0,<2.0.0"
For libraries, use more flexible version constraints:
[packages]
# Minimum version only
requests = ">=2.20.0"
# Upper bound to prevent incompatible versions
urllib3 = "<2.0.0"
pipenv scan to check for vulnerabilities* or very loose constraints in productionpipenv lockWhen specifying versions, consider:
If you encounter version conflicts:
# Try with verbose output to see the conflict
$ pipenv install --verbose
# Try relaxing version constraints
# Instead of requests==2.28.1, try requests~=2.28.0
If pip can't find a matching distribution:
--pre)If Pipenv can't resolve dependencies:
# Clear the cache and try again
$ pipenv lock --clear
Understanding version specifiers is crucial for effective dependency management with Pipenv. By using the right specifiers, you can balance stability, security, and flexibility in your Python projects.