Version Specifiers¶
This guide explains how to specify versions of packages and Python interpreters in Pipenv, including syntax, best practices, and advanced usage patterns.
Package Version Specifiers¶
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.
Basic Version Specifiers¶
Specifier |
Example |
Meaning |
|---|---|---|
|
|
Exact version |
|
|
Minimum version |
|
|
Maximum version |
|
|
Greater than version |
|
|
Less than version |
|
|
Not equal to version |
|
|
Compatible release (equivalent to |
|
|
Any version (not recommended for production) |
Combining Version Specifiers¶
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"
Note
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.
Compatible Release Operator¶
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).
Wildcard Versions¶
While not recommended for production, you can use wildcards:
# Install the latest version
$ pipenv install "requests==*"
# or simply
$ pipenv install requests
Pre-release Versions¶
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
Python Version Specifiers¶
Specifying Python Version for a Project¶
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"
Python Version vs. Full Version¶
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
Warning
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").
Python Version Selection Logic¶
When you run pipenv install without specifying a Python version:
Pipenv checks the
[requires]section in thePipfileIf
python_full_versionis specified, it tries to use that exact versionIf
python_versionis specified, it tries to find a compatible versionIf neither is specified, it uses the default Python interpreter
Advanced Version Specifiers¶
VCS Dependencies¶
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=requests
The 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"}
Local Path Dependencies¶
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"}
Remote File URL Dependencies¶
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.
Platform-Specific Dependencies¶
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'"}
Shorthand Marker Keys¶
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.
Platform Markers and Locking¶
Important
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.
Architecture-Specific Dependencies¶
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.
Python Version-Specific 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'"}
Complex Markers¶
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’)
Package Extras¶
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"]}
Package Categories¶
Pipenv supports organizing dependencies into different categories beyond the standard packages and dev-packages.
Defining Custom Categories¶
In your Pipfile:
[packages]
requests = "*"
[dev-packages]
pytest = "*"
[docs]
sphinx = "*"
sphinx-rtd-theme = "*"
[tests]
pytest-cov = "*"
Installing Specific Categories¶
# Install a package in a specific category
$ pipenv install sphinx --categories="docs"
# Install all packages from specific categories
$ pipenv install --categories="docs,tests"
Locking Specific Categories¶
# Lock only specific categories
$ pipenv lock --categories="docs,tests"
Best Practices¶
For Applications¶
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¶
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"
Security Considerations¶
Regularly update dependencies to get security fixes
Use
pipenv scanto check for vulnerabilitiesAvoid using
*or very loose constraints in productionConsider using hash verification with
pipenv lock
Dependency Resolution¶
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
Troubleshooting¶
Common Issues¶
Version Conflict Resolution¶
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
No Matching Distribution Found¶
If 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)
Dependency Resolution Failures¶
If Pipenv can’t resolve dependencies:
# Clear the cache and try again
$ pipenv lock --clear
Conclusion¶
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.