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 requestsBy 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 = trueYou 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.10This 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 versionOr 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:
- Pipenv checks the
[requires]section in thePipfile - If
python_full_versionis specified, it tries to use that exact version - If
python_versionis specified, it tries to find a compatible version - If neither is specified, it uses the default Python interpreter
You can install packages directly from version control systems:
# From a Git repository
$ pipenv install -e git+https://github.com/requests/requests.git@v2.31.0#egg=requestsThe format follows this pattern:
<vcs_type>+<scheme>://<location>/<user_or_organization>/<repository>@<branch_or_tag>#egg=<package_name>
Where:
<vcs_type>can begit,bzr,svn, orhg<scheme>can behttp,https,ssh, orfile@<branch_or_tag>is optional and specifies a specific branch, tag, or commit
This 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.gzThis 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"- Regularly update dependencies to get security fixes
- Use
pipenv scanto check for vulnerabilities - Avoid using
*or very loose constraints in production - Consider using hash verification with
pipenv lock
When specifying versions, consider:
- Compatibility: Ensure your constraints don't conflict with other packages
- Flexibility: Overly strict constraints can make dependency resolution difficult
- Security: Too loose constraints might introduce vulnerabilities
- Stability: Balance between getting updates and maintaining stability
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.0If pip can't find a matching distribution:
- Check that the version exists on PyPI
- Verify your version specifier syntax
- Consider if you need pre-release versions (
--pre)
If Pipenv can't resolve dependencies:
# Clear the cache and try again
$ pipenv lock --clearUnderstanding 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.