Skip site navigation (1)Skip section navigation (2)

  
 
  

home | help
VIRTUALENV(1)			   virtualenv			   VIRTUALENV(1)

NAME
     virtualenv  - virtualenv 21.2.3 Latest version on PyPI[image: PyPI - Imple-
     mentation] [image] [image: PyPI -	Python	Version]  [image]  Documentation
     statusDiscordPyPI	-  DownloadsPyPI - LicenseOpen issuesOpen pull requests-
     Package popularity

     virtualenv is a tool to create isolated Python environments.  Since  Python
     3.3, a subset of it has been integrated into the standard library under the
     venv  module.  For  how  virtualenv compares to the stdlib venv module, see
     Explanation.

QUICK NAVIGATION
     Tutorials - Learn by doing

     * Getting started a Create your first virtual environment and learn the ba-
       sic workflow

     How-to guides - Solve specific problems

     * Install virtualenv a Install virtualenv on your system

     * Use virtualenv a Select Python versions, activate environments, configure
       defaults, and use from Python code

     Reference - Technical information

     * Compatibility a Supported Python versions and operating systems

     * Command line a Command line options and flags

     * Python a Programmatic Python API reference

     Explanation - Understand the concepts

     * Explanation a How virtualenv works under the hood and why it exists

     Extensions

     * Plugins a Extend virtualenv with custom creators, seeders, and activators

RELATED PROJECTS
     Several tools build on virtualenv to provide higher-level workflows:

     * virtualenvwrapper a Shell wrapper for creating and managing multiple vir-
       tualenvs

     * pew a Python Env Wrapper, a set of commands to  manage  multiple  virtual
       environments

     * tox a Automate testing across multiple Python versions

     * nox a Flexible test automation in Python

EXTERNAL RESOURCES
     Learn more about virtualenv from these community resources:

     * Corey Schafer^as virtualenv tutorial a Video walkthrough for beginners

     * Bernat  Gabor^as status quo a Talk about the current state of Python pack-
       aging

     * Carl Meyer^as reverse-engineering a Deep dive into  how  virtualenv  works
       internally

   Getting started
     This  tutorial  will  teach  you  the basics of virtualenv through hands-on
     practice. Youall create your first virtual environment,  install  packages,
     and learn how to manage project dependencies.

   Prerequisites
     Before starting this tutorial, you need:

     * Python  3.8  or later installed on your system. If you use a version man-
       ager like pyenv, mise, or asdf, virtualenv  will  automatically	discover
       the Python version they manage.

     * virtualenv installed (see Install virtualenv).

   Create your first virtual environment
     Letas create a virtual environment called myproject:

	$ virtualenv myproject
	created virtual environment CPython3.13.2.final.0-64 in 200ms
	  creator CPython3Posix(dest=/home/user/myproject, clear=False, no_vcs_ignore=False, global=False)
	  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, via=copy, app_data_dir=/home/user/.cache/virtualenv)
	  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

     This  creates  a new directory called myproject containing a complete, iso-
     lated Python environment with its own copy of Python, pip, and other tools.

   Activate the environment
     To use your virtual environment, you can activate it. The	activation  com-
     mand differs by platform: [Linux/macOS]

	$ source myproject/bin/activate
     [Windows (PowerShell)]

	PS> .\myproject\Scripts\Activate.ps1
     [Windows (CMD)]

	C:\> .\myproject\Scripts\activate.bat

     After activation, your prompt changes to show the active environment:

	(myproject) $

     You  can verify that Python is now running from inside the virtual environ-
     ment: [Linux/macOS]

	(myproject) $ which python
	/home/user/myproject/bin/python
     [Windows (PowerShell)]

	(myproject) PS> where.exe python
	C:\Users\user\myproject\Scripts\python.exe
     [Windows (CMD)]

	(myproject) C:\> where.exe python
	C:\Users\user\myproject\Scripts\python.exe

   Install a package
     With the environment activated, install a package using pip:

	(myproject) $ pip install requests
	Collecting requests
	  Using cached requests-2.32.3-py3-none-any.whl (64 kB)
	Installing collected packages: requests
	Successfully installed requests-2.32.3

     Verify that the package is installed only inside your virtual environment:

	(myproject) $ python -c "import requests; print(requests.__file__)"
	/home/user/myproject/lib/python3.13/site-packages/requests/__init__.py

     The path shows that requests is installed in the virtual  environment,  not
     in your system Python.

   Deactivate
     When youare done working in the virtual environment, deactivate it:

	(myproject) $ deactivate
	$

     The  prompt  returns  to  normal,	and  Python commands now use your system
     Python again.

   Use without activation
     Activation is a convenience, not a requirement. You can run any  executable
     from the virtual environment directly by using its full path: [Linux/macOS]

	$ myproject/bin/python -c "import sys; print(sys.prefix)"
	/home/user/myproject

	$ myproject/bin/pip install httpx
     [Windows (PowerShell)]

	PS> .\myproject\Scripts\python.exe -c "import sys; print(sys.prefix)"
	C:\Users\user\myproject

	PS> .\myproject\Scripts\pip.exe install httpx
     [Windows (CMD)]

	C:\> .\myproject\Scripts\python.exe -c "import sys; print(sys.prefix)"
	C:\Users\user\myproject

	C:\> .\myproject\Scripts\pip.exe install httpx

     This  is  especially  useful in scripts, CI pipelines, and automation where
     modifying the shell environment is unnecessary.

   Set up a real project
     Now letas apply what youave learned to a real project workflow:

	$ mkdir myapp && cd myapp
	$ virtualenv venv
	$ source venv/bin/activate  # or use the appropriate command for your platform
	(venv) $ pip install flask requests
	(venv) $ pip freeze > requirements.txt

     The requirements.txt file now contains your projectas dependencies:

	blinker==1.9.0
	certifi==2025.1.31
	charset-normalizer==3.4.1
	click==8.1.8
	flask==3.1.0
	idna==3.10
	itsdangerous==2.2.0
	Jinja2==3.1.5
	MarkupSafe==3.0.2
	requests==2.32.3
	urllib3==2.3.0
	werkzeug==3.1.3

     This file lets you recreate the exact environment later. Letas test this:

	(venv) $ deactivate
	$ rm -rf venv
	$ virtualenv venv
	$ source venv/bin/activate
	(venv) $ pip install -r requirements.txt

     All packages are reinstalled exactly as before. Hereas the  complete  work-
     flow: [graph].SS What you learned

     In this tutorial, you learned how to:

     * Create a virtual environment with virtualenv.

     * Activate and deactivate virtual environments on different platforms.

     * Install packages in isolation from your system Python.

     * Save project dependencies with pip freeze.

     * Reproduce environments using requirements.txt.

   Next steps
     Now that you understand the basics, explore these topics:

     * Use  virtualenv	for  selecting specific Python versions, configuring de-
       faults, and advanced usage patterns.

     * Explanation for understanding how virtualenv works under the hood and how
       it compares to venv.

     * Command line for all available command line options and flags.

   Install virtualenv
     virtualenv is a command-line tool, so it should be installed in an isolated
     environment rather than into your system Python. Pick the method that  fits
     your setup:

     * uv a fast, modern Python package manager. Use this if you already have uv
       or are starting fresh.

     * pipx  a	installs  Python CLI tools in isolated environments. Use this if
       you already have pipx set up.

     * pip a the standard Python package installer. Use --user to avoid  modify-
       ing  system  packages. May not work on distributions with externally-man-
       aged Python environments.

     * zipapp a a self-contained executable requiring no installation.	Use this
       in CI or environments where you cannot install packages.
     [graph][uv] Install virtualenv as a uv tool:

	$ uv tool install virtualenv

     Install the development version:

	$ uv tool install git+https://github.com/pypa/virtualenv.git@main
     [pipx] Install virtualenv using pipx:

	$ pipx install virtualenv

     Install the development version:

	$ pipx install git+https://github.com/pypa/virtualenv.git@main
     [pip] Install virtualenv using pip:

	$ python -m pip install --user virtualenv

     Install the development version:

	$ python -m pip install git+https://github.com/pypa/virtualenv.git@main

     WARNING:
	Some Linux distributions use system-managed Python environments. If  you
	encounter  errors  about externally-managed environments, use uv tool or
	pipx instead.
     [zipapp] Download the zipapp file and run it directly:

	$ python virtualenv.pyz --help

     Download the latest version  from	https://bootstrap.pypa.io/virtualenv.pyz
     or  a  specific  version from https://bootstrap.pypa.io/virtualenv/x.y/vir-
     tualenv.pyz.

   Verify installation
     Check the installed version:

	$ virtualenv --version

     See Compatibility for supported Python versions.

   Use virtualenv
   Select a Python version
     By default, virtualenv uses the same Python version it runs under. Override
     this with --python or -p.

   Using version specifiers
     Specify a Python version by name or version number:

	$ virtualenv -p python3.8 venv
	$ virtualenv -p 3.10 venv
	$ virtualenv -p pypy3 venv
	$ virtualenv -p rustpython venv

   Using PEP 440 specifiers
     Use PEP 440 version specifiers to match Python versions:

	$ virtualenv --python ">=3.12" venv
	$ virtualenv --python "~=3.11.0" venv
	$ virtualenv --python "cpython>=3.10" venv

     * >=3.12 a any Python 3.12 or later.

     * ~=3.11.0 a compatible  release,	equivalent  to	>=3.11.0,  <3.12.0  (any
       3.11.x patch).

     * cpython>=3.10 a restrict to CPython implementation, 3.10 or later.

   Using free-threading Python
     Create an environment with free-threading Python:

	$ virtualenv -p 3.13t venv

   Targeting a specific CPU architecture
     On  machines  that  support  multiple architectures a such as Apple Silicon
     (arm64 + x86_64 via Rosetta) or Windows on ARM a you can request a specific
     CPU architecture by appending it to the spec string:

	$ virtualenv -p cpython3.12-64-arm64 venv
	$ virtualenv -p 3.11-64-x86_64 venv

     Cross-platform aliases are normalized automatically, so  amd64  and  x86_64
     are treated as equivalent, as are aarch64 and arm64. If omitted, any archi-
     tecture matches (preserving existing behavior).

   Using absolute paths
     Specify the full path to a Python interpreter:

	$ virtualenv -p /usr/bin/python3.9 venv

   Using --try-first-with
     Use  --try-first-with  to provide a hint about which Python to check first.
     Unlike --python, this is a hint rather than a rule. The interpreter at this
     path is checked first, but only used if it matches the --python constraint.

	$ virtualenv --python ">=3.10" --try-first-with /usr/bin/python3.9 venv

     In this example, /usr/bin/python3.9 is checked first but  rejected  because
     it does not satisfy the >=3.10 constraint.

   Using version managers (pyenv, mise, asdf)
     virtualenv  automatically	resolves shims from pyenv, mise, and asdf to the
     real Python binary. Set the active Python version using any of the standard
     mechanisms and virtualenv will discover it:

	$ pyenv local 3.12.0
	$ virtualenv venv  # uses pyenv's 3.12.0, not the system Python

	$ PYENV_VERSION=3.11.0 virtualenv venv	# uses 3.11.0

     This also works with mise and asdf:

	$ mise use python@3.12
	$ virtualenv venv

     No additional configuration is required. See Explanation for details on how
     shim resolution works.

   Activate a virtual environment
     Activate the environment to modify your shellas PATH and environment  vari-
     ables.  [Bash/Zsh]

	$ source venv/bin/activate
     [Fish]

	$ source venv/bin/activate.fish
     [PowerShell]

	PS> .\venv\Scripts\Activate.ps1

     NOTE:
	If  you encounter an execution policy error, run Set-ExecutionPolicy Re-
	moteSigned to allow local scripts.
     [CMD]

	> .\venv\Scripts\activate.bat
     [Nushell]

	$ overlay use venv/bin/activate.nu

   Deactivate the environment
     Exit the virtual environment:

	$ deactivate

   Use without activation
     Use the environment without activating it by calling executables with their
     full paths:

	$ venv/bin/python script.py
	$ venv/bin/pip install package

   Customize prompt
     Set a custom prompt prefix:

	$ virtualenv --prompt myproject venv

     Disable the prompt modification by setting  the  VIRTUAL_ENV_DISABLE_PROMPT
     environment variable.

     Access the prompt string via the VIRTUAL_ENV_PROMPT environment variable.

   Programmatic activation
     Activate  the  environment from within a running Python process using acti-
     vate_this.py. This modifies sys.path and environment variables in the  cur-
     rent  process  so that subsequent imports resolve from the virtual environ-
     ment.

	import runpy

	runpy.run_path("venv/bin/activate_this.py")

     A common use case is web applications served by a system-wide  WSGI  server
     (such as mod_wsgi or uWSGI) that need to load packages from a virtual envi-
     ronment:

	import runpy
	from pathlib import Path

	runpy.run_path(str(Path("/var/www/myapp/venv/bin/activate_this.py")))

	from myapp import create_app  # noqa: E402

	application = create_app()

   Configure defaults
     Use a configuration file to set default options for virtualenv.

   Configuration file location
     The  configuration file is named virtualenv.ini and located in the platfor-
     mdirs app config directory. Run virtualenv --help to see the exact location
     for your system.

     Override the location with the VIRTUALENV_CONFIG_FILE environment variable.

   Configuration format
     Derive configuration keys from command-line options by stripping leading  -
     and replacing remaining - with _:

	[virtualenv]
	python = /opt/python-3.8/bin/python

   Multi-value options
     Specify multiple values on separate lines:

	[virtualenv]
	extra_search_dir =
	    /path/to/dists
	    /path/to/other/dists

   Environment variables
     Set options using environment variables with the VIRTUALENV_ prefix and up-
     percase key names:

	$ export VIRTUALENV_PYTHON=/opt/python-3.8/bin/python

     For multi-value options, separate values with commas or newlines.

   Override app-data location
     Set  the  VIRTUALENV_OVERRIDE_APP_DATA environment variable to override the
     default app-data cache directory location.

   Configuration priority
     Options are resolved in this order (highest to lowest priority): [graph].SS
     Control seed packages

   Upgrade embedded wheels
     Update the embedded wheel files to the latest versions:

	$ virtualenv --upgrade-embed-wheels

   Provide custom wheels
     Use custom wheel files from a local directory:

	$ virtualenv --extra-search-dir /path/to/wheels venv

   Download latest from PyPI
     Download the latest versions of seed packages from PyPI:

	$ virtualenv --download venv

   Disable periodic updates
     Disable automatic periodic updates of seed packages:

	$ virtualenv --no-periodic-update venv

   For distribution maintainers
     Patch  the  virtualenv.seed.wheels.embed  module	and   set   PERIODIC_UP-
     DATE_ON_BY_DEFAULT  to  False  to	disable periodic updates by default. See
     Explanation for implementation details.

   Use from Python code
     Call virtualenv from Python code using the cli_run function:

	from virtualenv import cli_run

	cli_run(["venv"])

     Pass options as list elements:

	cli_run(["-p", "python3.8", "--without-pip", "myenv"])

     Use the returned session object to access environment details:

	result = cli_run(["venv"])
	print(result.creator.dest)  # path to created environment
	print(result.creator.exe)  # path to python executable

     Use session_via_cli to describe the environment without creating it:

	from virtualenv import session_via_cli

	session = session_via_cli(["venv"])
	# inspect session.creator, session.seeder, session.activators

     See Python for complete API documentation.

   Compatibility
   Supported Python implementations
     virtualenv works with the	following  Python  interpreter	implementations.
     Only  the	latest	patch  version of each minor version is fully supported;
     previous patch versions work on a best effort basis.

   CPython
     3.14 >= python_version >= 3.8

   PyPy
     3.11 >= python_version >= 3.8

   GraalPy
     24.1 and later (Linux and macOS only).

   RustPython
     Experimental support (Linux, macOS,  and  Windows).  RustPython  implements
     Python 3.14.

   Support policy
     * New  versions are added close to their release date, typically during the
       beta phase.

     * Old versions are dropped 18 months after CPython EOL, giving users plenty
       of time to migrate.

   Version support timeline
     Major version support changes:

     * 20.27.0 (2024-10-17): dropped support for running under	Python	3.7  and
       earlier.

     * 20.22.0	(2023-04-19):  dropped	support  for  creating	environments for
       Python 3.6 and earlier.

     * 20.18.0 (2023-02-06): dropped support for running under	Python	3.6  and
       earlier.

   Supported operating systems
     CPython  is shipped in multiple forms, and each OS repackages it, often ap-
     plying some customization. The platforms listed below are tested.	Unlisted
     platforms	may  work but are not explicitly supported. If you encounter is-
     sues on unlisted platforms, please open a feature request.

   Cross-platform
     These Python distributions work on Linux, macOS, and Windows:

     * Installations from python.org

     * python-build-standalone builds (used by uv and mise)

     * Python versions managed by pyenv, mise, or asdf (shims are  automatically
       resolved to the real binary)

   Linux
     * Ubuntu 16.04 and later (both upstream and deadsnakes builds)

     * Fedora

     * RHEL and CentOS

     * OpenSuse

     * Arch Linux

   macOS
     * Python  versions  installed  via  Homebrew  (works, but not recommended a
       Homebrew may upgrade or remove Python versions without warning,	breaking
       existing virtual environments)

     * Python  3  part	of  XCode  (Python  framework  builds at /Library/Frame-
       works/Python3.framework/)

     NOTE:
	Framework builds do not support  copy-based  virtual  environments.  Use
	symlink or hardlink creation methods instead.

   Windows
     * Windows Store Python 3.8 and later

   Command line
     virtualenv is primarily a command line application. All options have sensi-
     ble  defaults,  and there is one required argument: the name or path of the
     virtual environment to create.

     See Use virtualenv for how to select Python versions,  configure  defaults,
     and use environment variables.

   Command line options
     virtualenv [OPTIONS]
	 +-----------------+----------------------+----------------------+
	 | Named Arguments |			  |			 |
	 +-----------------+----------------------+----------------------+
	 |		   | '==SUPPRESS=='	  | display  the version |
	 |		   |			  | of	the   virtualenv |
	 |		   |			  | package  and its lo- |
	 |		   |			  | cation, then exit	 |
	 +-----------------+----------------------+----------------------+
	 |		   | False		  | on failure also dis- |
	 |		   |			  | play the  stacktrace |
	 |		   |			  | internals	of  vir- |
	 |		   |			  | tualenv		 |
	 +-----------------+----------------------+----------------------+
	 |		   | False		  | use app data  folder |
	 |		   |			  | in	 read-only  mode |
	 |		   |			  | (write    operations |
	 |		   |			  | will  fail	with er- |
	 |		   |			  | ror)		 |
	 +-----------------+----------------------+----------------------+
	 |		   | platform	 specific | a data  folder  used |
	 |		   | application     data | as cache by the vir- |
	 |		   | folder		  | tualenv		 |
	 +-----------------+----------------------+----------------------+
	 |		   | False		  | start with empty app |
	 |		   |			  | data folder 	 |
	 +-----------------+----------------------+----------------------+
	 |		   | False		  | trigger a manual up- |
	 |		   |			  | date of the embedded |
	 |		   |			  | wheels		 |
	 +-----------------+----------------------+----------------------+
		 +----------------------+---+--------------------+
		 | verbosity   a   ver- |   |			 |
		 | bosity =  verbose  - |   |			 |
		 | quiet, default INFO, |   |			 |
		 | mapping   =>  CRITI- |   |			 |
		 | CAL=0,      ERROR=1, |   |			 |
		 | WARNING=2,	INFO=3, |   |			 |
		 | DEBUG=4, NOTSET=5	|   |			 |
		 +----------------------+---+--------------------+
		 |			| 2 | increase verbosity |
		 +----------------------+---+--------------------+
		 |			| 0 | decrease verbosity |
		 +----------------------+---+--------------------+

   discovery
       +----------------------+----------------------+----------------------+
       | core	 a    options | 		     |			    |
       | shared   across  all | 		     |			    |
       | discovery	      | 		     |			    |
       +----------------------+----------------------+----------------------+
       |		      | 'builtin'	     | interpreter  discov- |
       |		      | 		     | ery  method;  choice |
       |		      | 		     | of: builtin	    |
       +----------------------+----------------------+----------------------+
       |		      | the   python	exe- | interpreter based on |
       |		      | cutable   virtualenv | what to create envi- |
       |		      | is installed into    | ronment	(path/iden- |
       |		      | 		     | tifier/version-spec- |
       |		      | 		     | ifier)  - by default |
       |		      | 		     | use the	interpreter |
       |		      | 		     | where  the  tool  is |
       |		      | 		     | installed  -   first |
       |		      | 		     | found  wins. Version |
       |		      | 		     | specifiers    (e.g., |
       |		      | 		     | >=3.12,	  ~=3.11.0, |
       |		      | 		     | ==3.10)	 are   also |
       |		      | 		     | supported	    |
       +----------------------+----------------------+----------------------+
       |		      | []		     | try  first these in- |
       |		      | 		     | terpreters    before |
       |		      | 		     | starting the discov- |
       |		      | 		     | ery		    |
       +----------------------+----------------------+----------------------+

   creator
       +----------------------+----------------------+----------------------+
       | core	 a    options | 		     |			    |
       | shared  across   all | 		     |			    |
       | creator	      | 		     |			    |
       +----------------------+----------------------+----------------------+
       |		      | builtin   if  exist, | create	environment |
       |		      | else venv	     | via;    choice	of: |
       |		      | 		     | cpython3-mac-brew,   |
       |		      | 		     | cpython3-mac-frame-  |
       |		      | 		     | work,		    |
       |		      | 		     | cpython3-posix,	    |
       |		      | 		     | cpython3-win,	    |
       |		      | 		     | graalpy-posix,	    |
       |		      | 		     | graalpy-win,	    |
       |		      | 		     | pypy3-posix,	    |
       |		      | 		     | pypy3-win,     rust- |
       |		      | 		     | python-posix,  rust- |
       |		      | 		     | python-win, venv     |
       +----------------------+----------------------+----------------------+
       |		      | 		     | directory to  create |
       |		      | 		     | virtualenv at	    |
       +----------------------+----------------------+----------------------+
       |		      | False		     | remove  the destina- |
       |		      | 		     | tion  directory	 if |
       |		      | 		     | exist  before start- |
       |		      | 		     | ing (will  overwrite |
       |		      | 		     | files otherwise)     |
       +----------------------+----------------------+----------------------+
       |		      | False		     | don't create VCS ig- |
       |		      | 		     | nore   directive  in |
       |		      | 		     | the destination	di- |
       |		      | 		     | rectory		    |
       +----------------------+----------------------+----------------------+
       |		      | False		     | give the virtual en- |
       |		      | 		     | vironment  access to |
       |		      | 		     | the	     system |
       |		      | 		     | site-packages dir    |
       +----------------------+----------------------+----------------------+
       |		      | True		     | try  to use symlinks |
       |		      | 		     | rather than  copies, |
       |		      | 		     | when   symlinks	are |
       |		      | 		     | not the default	for |
       |		      | 		     | the platform	    |
       +----------------------+----------------------+----------------------+
       |		      | False		     | try  to	use  copies |
       |		      | 		     | rather	than   sym- |
       |		      | 		     | links,	even   when |
       |		      | 		     | symlinks are the de- |
       |		      | 		     | fault for the  plat- |
       |		      | 		     | form		    |
       +----------------------+----------------------+----------------------+

   seeder
	    +----------------------+------------+----------------------+
	    | core    a    options |		|		       |
	    | shared  across   all |		|		       |
	    | seeder		   |		|		       |
	    +----------------------+------------+----------------------+
	    |			   | 'app-data' | seed	 packages  in- |
	    |			   |		| stall method; choice |
	    |			   |		| of: app-data, pip    |
	    +----------------------+------------+----------------------+
	    |			   | False	| do not install  seed |
	    |			   |		| packages	       |
	    +----------------------+------------+----------------------+
	    |			   | True	| pass	  to   disable |
	    |			   |		| download of the lat- |
	    |			   |		| est	    pip/setup- |
	    |			   |		| tools/wheel	  from |
	    |			   |		| PyPI		       |
	    +----------------------+------------+----------------------+
	    |			   | False	| pass to enable down- |
	    |			   |		| load of  the	latest |
	    |			   |		| pip/setuptools/wheel |
	    |			   |		| from PyPI	       |
	    +----------------------+------------+----------------------+
	    |			   | [] 	| a   path  containing |
	    |			   |		| wheels to extend the |
	    |			   |		| internal wheel  list |
	    |			   |		| (can	 be   set   1+ |
	    |			   |		| times)	       |
	    +----------------------+------------+----------------------+
	    |			   | 'bundle'	| version  of  pip  to |
	    |			   |		| install as seed: em- |
	    |			   |		| bed, bundle, none or |
	    |			   |		| exact version        |
	    +----------------------+------------+----------------------+
	    |			   | 'none'	| version   of	setup- |
	    |			   |		| tools to install  as |
	    |			   |		| seed: embed, bundle, |
	    |			   |		| none	or  exact ver- |
	    |			   |		| sion		       |
	    +----------------------+------------+----------------------+
	    |			   | False	| do not install pip   |
	    +----------------------+------------+----------------------+
	    |			   | False	| do not  install  se- |
	    |			   |		| tuptools	       |
	    +----------------------+------------+----------------------+
	    |			   | False	| disable the periodic |
	    |			   |		| (once every 14 days) |
	    |			   |		| update of the embed- |
	    |			   |		| ded wheels	       |
	    +----------------------+------------+----------------------+
	      +----------------------+-------+----------------------+
	      | app-data  a  options |	     |			    |
	      | specific  to  seeder |	     |			    |
	      | app-data	     |	     |			    |
	      +----------------------+-------+----------------------+
	      | 		     | False |	symlink  the python |
	      | 		     |	     | packages  from	the |
	      | 		     |	     | app-data folder (re- |
	      | 		     |	     | quires	       seed |
	      | 		     |	     | pip>=19.3)	    |
	      +----------------------+-------+----------------------+

   activators
       +----------------------+----------------------+----------------------+
       | core	 a    options | 		     |			    |
       | shared   across  all | 		     |			    |
       | activators	      | 		     |			    |
       +----------------------+----------------------+----------------------+
       |		      | comma separated list | activators to gener- |
       |		      | of  activators	sup- | ate - default is all |
       |		      | ported		     | supported;    choice |
       |		      | 		     | of:   bash,   batch, |
       |		      | 		     | cshell,	      fish, |
       |		      | 		     | nushell, powershell, |
       |		      | 		     | python		    |
       +----------------------+----------------------+----------------------+
       |		      | 		     | provides an alterna- |
       |		      | 		     | tive  prompt  prefix |
       |		      | 		     | for this environment |
       |		      | 		     | (value  of  .  means |
       |		      | 		     | name of the  current |
       |		      | 		     | working directory)   |
       +----------------------+----------------------+----------------------+

   Python
     The  primary  interface to virtualenv is the command line application. How-
     ever, it can also be used programmatically via the virtualenv.cli_run func-
     tion and the Session class.

     See Use virtualenv for usage examples.

   virtualenv module
     virtualenv.cli_run(args, options=None, setup_logging=True, env=None)
	    Create a virtual environment given some command line interface argu-
	    ments.

	    Parameters

		   * args (list[str]) -- the command line arguments

		   * options (Optional[VirtualEnvOptions]) -- passing in a  Vir-
		     tualEnvOptions object allows return of the parsed options

		   * setup_logging  (bool)  --	True  if setup logging handlers,
		     False to use handlers already registered

		   * env  (Optional[MutableMapping[str,  str]])  --  environment
		     variables to use

	    Return type
		   Session

	    Returns
		   the	session object of the creation (its structure for now is
		   experimental and might change on short notice)

     virtualenv.session_via_cli(args, options=None, setup_logging=True,
     env=None)
	    Create a virtualenv session (same as cli_run, but this does not per-
	    form the creation). Use this if you just want to query what the vir-
	    tual environment would look like, but not actually create it.

	    Parameters

		   * args (list[str]) -- the command line arguments

		   * options (Optional[VirtualEnvOptions]) -- passing in a  Vir-
		     tualEnvOptions object allows return of the parsed options

		   * setup_logging  (bool)  --	True  if setup logging handlers,
		     False to use handlers already registered

		   * env  (Optional[MutableMapping[str,  str]])  --  environment
		     variables to use

	    Return type
		   Session

	    Returns
		   the	session object of the creation (its structure for now is
		   experimental and might change on short notice)

   Session class
     The Session class represents a virtualenv creation session and provides ac-
     cess to the created environment's properties.

     class virtualenv.run.session.Session(verbosity, app_data, interpreter, cre-
     ator, seeder, activators)
	    Represents a virtual environment creation session.

	    Parameters

		   * verbosity (int)

		   * app_data (AppData)

		   * interpreter (PythonInfo)

		   * creator (Creator)

		   * seeder (Seeder)

		   * activators (list[Activator])

	    property verbosity: int
		   The verbosity of the run.

	    property interpreter: PythonInfo
		   Create a virtual environment based on this  reference  inter-
		   preter.

	    property creator: Creator
		   The	creator  used  to build the virtual environment (must be
		   compatible with the interpreter).

	    property seeder: Seeder
		   The mechanism used to provide the seed packages (pip,  setup-
		   tools, wheel).

	    property activators: list[Activator]
		   Activators used to generate activations scripts.

   VirtualEnvOptions
     Options  namespace  passed  to plugin constructors, populated from the CLI,
     environment variables, and configuration files.

     class virtualenv.config.cli.parser.VirtualEnvOptions(**kwargs)

	    Parameters
		   kwargs (Any)

	    set_src(key, value, src)
		   Set an option value and record where it came from.

		   Parameters

			  * key (str) -- the option name

			  * value (Any) -- the option value

			  * src (str) -- the source of the  value  (e.g.  "cli",
			    "env var", "default")

		   Return type
			  None

	    get_source(key)
		   Return the source that provided a given option value.

		   Parameters
			  key (str) -- the option name

		   Return type
			  Optional[str]

		   Returns
			  the  source string (e.g. "cli", "env var", "default"),
			  or None if not tracked

	    property verbosity: int | None
		   The verbosity level, computed as verbose - quiet, clamped  to
		   zero.

		   Returns
			  the  verbosity level, or None if neither --verbose nor
			  --quiet has been parsed yet

   Explanation
     This page explains the design decisions and concepts behind virtualenv.  It
     focuses on understanding why things work the way they do.

   virtualenv vs venv vs uv
     Since Python 3.3, the standard library includes the venv module, which pro-
     vides  basic virtual environment creation following PEP 405. uv is a newer,
     Rust-based tool that also creates virtual environments via uv venv.

     virtualenv occupies a middle ground: faster and more featureful than  venv,
     while remaining a pure Python solution with a plugin system for extensibil-
     ity.
   +------------------+------------------+------------------+------------------+
   |		      | venv		 | virtualenv	    | uv	       |
   +------------------+------------------+------------------+------------------+
   | Performance      | Slowest  (60s+); | Fast;     caches | Fastest;	  Rust |
   |		      | spawns pip as  a | pre-built	in- | implementation,  |
   |		      | subprocess    to | stall    images, | milliseconds.    |
   |		      | seed.		 | subsequent  cre- | Does  not   seed |
   |		      | 		 | ation <  1  sec- | pip/setuptools   |
   |		      | 		 | ond. 	    | by default.      |
   +------------------+------------------+------------------+------------------+
   | Extensibility    | No  plugin  sys- | Plugin    system | No  plugin  sys- |
   |		      | tem.		 | for	 discovery, | tem.	       |
   |		      | 		 | creation,  seed- |		       |
   |		      | 		 | ing, and activa- |		       |
   |		      | 		 | tion.	    |		       |
   +------------------+------------------+------------------+------------------+
   | Cross-version    | Only the  Python | Any	  installed | Any installed or |
   |		      | version  it runs | Python	via | uv-managed       |
   |		      | under.		 | auto-discovery   | Python.	       |
   |		      | 		 | (registry,	    |		       |
   |		      | 		 | uv-managed,	    |		       |
   |		      | 		 | PATH).	    |		       |
   +------------------+------------------+------------------+------------------+
   | Upgradeability   | Tied  to  Python | Independent	via | Independent  via |
   |		      | releases.	 | PyPI.	    | its  own release |
   |		      | 		 |		    | cycle.	       |
   +------------------+------------------+------------------+------------------+
   | Programmatic API | Basic	create() | Full Python API; | Command	  line |
   |		      | function only.	 | can describe en- | only.	       |
   |		      | 		 | vironments with- |		       |
   |		      | 		 | out	   creating |		       |
   |		      | 		 | them. Used by  - |		       |
   |		      | 		 | tox,  poetry,  - |		       |
   |		      | 		 | pipx, etc.	    |		       |
   +------------------+------------------+------------------+------------------+
   | Type annotations | No	py.typed | Fully typed with | Not   applicable |
   |		      | marker;  limited | PEP 561 py.typed | (Rust binary).   |
   |		      | annotations.	 | marker;  checked |		       |
   |		      | 		 | by ty.	    |		       |
   +------------------+------------------+------------------+------------------+
   | Best for	      | Zero   dependen- | Plugin  extensi- | Maximum	speed, |
   |		      | cies,	   basic | bility, program- | already using uv |
   |		      | needs.		 | matic API,  tool | for package man- |
   |		      | 		 | compatibility (- | agement.	       |
   |		      | 		 | tox, 	  - |		       |
   |		      | 		 | virtualenvwrap-  |		       |
   |		      | 		 | per).	    |		       |
   +------------------+------------------+------------------+------------------+
     [graph].SS How virtualenv works

     Python  packaging often faces a fundamental problem: different applications
     require different versions of the same library. If Application A needs  re-
     quests==2.25.1  but  Application  B needs requests==2.28.0, installing both
     into the global site-packages directory creates a conflict. Only  one  ver-
     sion can exist in a given location.

     virtualenv solves this by creating isolated Python environments. Each envi-
     ronment  has  its own installation directories and can maintain its own set
     of installed packages, independent of other  environments	and  the  system
     Python.

     virtualenv operates in two distinct phases: [graph].INDENT 0.0

     Phase 1: Discover a Python interpreter
	    virtualenv	first  identifies which Python interpreter to use as the
	    template for the virtual environment. By default, it uses  the  same
	    Python  version  that virtualenv itself is running on. You can over-
	    ride this with the --python flag to specify a different interpreter.

     Phase 2: Create the virtual environment
	    Once the target interpreter is identified,	virtualenv  creates  the
	    environment in four steps:

	    1. Create a Python executable matching the target interpreter

	    2. Install	seed packages (pip, setuptools, wheel) to enable package
	       installation

	    3. Install activation scripts for various shells

	    4. Create VCS ignore files (currently Gitas  .gitignore,  skip  with
	       --no-vcs-ignore)

An  important  design  principle: virtual environments are not self-contained. A
complete Python installation consists of thousands of files, and copying all  of
them into every virtual environment would be wasteful. Instead, virtual environ-
ments  are  lightweight  shells that borrow most content from the system Python.
They contain only whatas needed to redirect Pythonas behavior.

This design has two implications:

     * Environment creation is fast because only a small number of files need to
       be created.

     * Upgrading the system Python might affect existing  virtual  environments,
       since  they reference the system Pythonas standard library and binary ex-
       tensions.

     The Python executable in a virtual environment is effectively isolated from
     the one used to create it, but the supporting files are shared.

     WARNING:
	If you upgrade your system Python, existing  virtual  environments  will
	still  report  the  old  version  (the version number is embedded in the
	Python executable itself), but they will use the new versionas	standard
	library  and  binary extensions. This normally works without issues, but
	be aware that the environment is effectively running a hybrid of old and
	new Python versions.

   Python discovery
     Before creating a virtual environment, virtualenv must locate a Python  in-
     terpreter. The interpreter determines the virtual environmentas Python ver-
     sion,  implementation  (CPython,  PyPy,  etc.), and architecture (32-bit or
     64-bit).

     The --python flag accepts several specifier formats:

     Path specifier
	    An absolute or  relative  path  to	a  Python  executable,	such  as
	    /usr/bin/python3.8 or ./python.

     Version specifier
	    A  string  following  the format {implementation}{version}{architec-
	    ture}{machine} where:

	    * Implementation is alphabetic characters (python means  any  imple-
	      mentation; if omitted, defaults to python).

	    * Version  is  dot-separated  numbers,  optionally followed by t for
	      free-threading builds.

	    * Architecture is -64 or -32 (if omitted, means any architecture).

	    * Machine is the CPU  instruction  set  architecture,  e.g.  -arm64,
	      -x86_64,	-aarch64 (if omitted, means any machine). Cross-platform
	      aliases are normalized automatically (amd64 a  x86_64,  aarch64  a
	      arm64).

	    Examples:

	    * python3.8.1 - Any Python implementation with version 3.8.1

	    * 3 - Any Python implementation with major version 3

	    * 3.13t - Any Python implementation version 3.13 with free-threading
	      enabled

	    * cpython3 - CPython implementation with major version 3

	    * pypy2 - PyPy implementation with major version 2

	    * cpython3.12-64-arm64 - CPython 3.12, 64-bit, ARM64 architecture

	    * 3.11-64-x86_64  - Any implementation, version 3.11, 64-bit, x86_64
	      architecture

	    * rustpython - RustPython implementation

     PEP 440 version specifier
	    Version constraints using PEP 440 operators:

	    * >=3.12 - Any Python 3.12 or later

	    * ~=3.11.0 - Compatible with Python 3.11.0

	    * cpython>=3.10 - CPython 3.10 or later

     When you provide a specifier, virtualenv searches for matching interpreters
     using this strategy: [graph].INDENT 0.0

     1. Windows Registry (Windows only): Check registered  Python  installations
	per PEP 514.

     2. uv-managed  installations:  Check  the UV_PYTHON_INSTALL_DIR environment
	variable or platform-specific uv Python directories for  managed  Python
	installations.

     3. PATH  search:  Search  for  executables on the PATH environment variable
	with names matching the specification.

   Version manager shim resolution
     Version managers like pyenv, mise, and asdf place lightweight shim  scripts
     on  PATH that delegate to the real Python binary. When virtualenv discovers
     a Python interpreter by running it as a subprocess, shims	may  resolve  to
     the  wrong  Python version (typically the system Python) because the shimas
     resolution logic depends on shell	environment  state  that  doesnat  fully
     propagate to child processes.

     virtualenv detects shims by checking whether the candidate executable lives
     in  a  known  shim  directory  ($PYENV_ROOT/shims, $MISE_DATA_DIR/shims, or
     $ASDF_DATA_DIR/shims). When a shim is detected, virtualenv bypasses it  and
     locates  the  real binary directly under the version manageras versions di-
     rectory, using the active version from:

     1. The PYENV_VERSION environment  variable  (colon-separated  for	multiple
	versions).

     2. A .python-version file in the current directory or any parent directory.

     3. The global version file at $PYENV_ROOT/version.

     This convention is shared across pyenv, mise, and asdf, so the same resolu-
     tion logic works for all three.

     WARNING:
	Virtual  environments  typically  reference the system Pythonas standard
	library. If you upgrade the system Python, the virtual environment  will
	report	the old version (embedded in its Python executable) but will ac-
	tually use the new versionas standard library content.	This  can  cause
	confusion when debugging version-specific behavior.

	If you use a virtual environmentas Python as the target for creating an-
	other virtual environment, virtualenv will detect the system Python ver-
	sion  and  create an environment matching the actual (upgraded) version,
	not the version reported by the virtual environment.

   Creators
     Creators are responsible for constructing the  virtual  environment  struc-
     ture. virtualenv supports two types of creators:

     venv creator
	    This  creator  delegates the entire creation process to the standard
	    libraryas venv module, following PEP 405. The venv creator	has  two
	    limitations:

	    * It only works with Python 3.5 or later.

	    * It  requires  spawning a subprocess to invoke the venv module, un-
	      less virtualenv is installed in the system Python.

	    The subprocess overhead can be significant,  especially  on  Windows
	    where process creation is expensive.

     builtin creator
	    This  creator means virtualenv performs the creation itself by know-
	    ing exactly which files to create and which system files  to  refer-
	    ence.  The	builtin creator is actually a family of specialized cre-
	    ators for different combinations of Python implementation  (CPython,
	    PyPy,  GraalPy,  RustPython) and platform (Windows, POSIX). The name
	    builtin is an alias that selects the first available builtin creator
	    for the target environment.

	    Because builtin creators donat require subprocess  invocation,  the-
	    yare generally faster than the venv creator.
     [graph]

     virtualenv  defaults  to  using the builtin creator if one is available for
     the target environment, falling back to the venv creator otherwise.

   Seeders
     After creating the virtual environment structure, virtualenv installs  seed
     packages  that  enable  package management within the environment. The seed
     packages are:

     * pip - The package installer for Python (always installed).

     * setuptools - Package development and installation  library  (disabled  by
       default on Python 3.12+).

     * wheel  -  Support  for the wheel binary package format (only installed by
       default on Python 3.8).

     virtualenv supports two seeding methods with dramatically different perfor-
     mance characteristics:

     pip seeder
	    This method uses the bundled pip wheel to install seed  packages  by
	    spawning a child pip process. The subprocess performs a full instal-
	    lation,  including	unpacking  wheels  and generating metadata. This
	    method is reliable but slow, typically consuming 98%  of  the  total
	    virtual environment creation time.

     app-data seeder
	    This  method  creates  reusable install images in a user application
	    data directory. The first time you create an environment  with  spe-
	    cific seed package versions, the app-data seeder builds complete in-
	    stall  images  and	stores them in the cache. Subsequent environment
	    creations simply link or copy these pre-built images into  the  vir-
	    tual environmentas site-packages directory.

	    Performance comparison for creating virtual environments: [graph]

	    On	platforms  that support symlinks efficiently (Linux, macOS), the
	    app-data seeder provides nearly instant seeding.

	    You can override  the  cache  location  using  the	VIRTUALENV_OVER-
	    RIDE_APP_DATA environment variable.

   Wheel acquisition
     Both  seeding methods require wheel files for the seed packages. virtualenv
     acquires wheels using a priority system: [graph].INDENT 0.0

     Embedded wheels
	    virtualenv ships with a set of  wheels  bundled  directly  into  the
	    package.  These are tested with the virtualenv release and provide a
	    baseline set of seed packages.  Different  Python  versions  require
	    different package versions, so virtualenv bundles multiple wheels to
	    support its wide Python version range.

     Upgraded embedded wheels
	    Users can manually upgrade the embedded wheels by running virtualenv
	    with the --upgrade-embed-wheels flag. This fetches newer versions of
	    seed packages from PyPI and stores them in the user application data
	    directory. Subsequent virtualenv invocations will use these upgraded
	    wheels instead of the embedded ones.

	    virtualenv can also perform periodic automatic upgrades (see below).

     Extra search directories
	    Users can specify additional directories containing wheels using the
	    --extra-search-dir	flag.  This is useful in air-gapped environments
	    or when using custom package builds.

     PyPI download
	    If no suitable wheel is found in the  above  locations,  or  if  the
	    --download flag is set, virtualenv will use pip to download the lat-
	    est compatible version from PyPI.

   Periodic update mechanism
     To  keep  the  seed  packages reasonably current without requiring users to
     manually upgrade virtualenv or run --upgrade-embed-wheels,  virtualenv  im-
     plements a periodic automatic update system: [graph]

     The  28-day waiting period protects users from automatically adopting newly
     released packages that might contain bugs.  The 1-hour delay after download
     ensures continuous integration systems donat start using different  package
     versions mid-run, which could cause confusing test failures.

     You can disable the periodic update mechanism with the --no-periodic-update
     flag.

   Distribution maintainer patching
     Operating	system distributions and package managers sometimes need to cus-
     tomize which seed package versions virtualenv uses. They want to align vir-
     tualenvas bundled packages with system package versions.

     Distributions can patch the virtualenv.seed.wheels.embed module,  replacing
     the  get_embed_wheel  function  with  their own implementation that returns
     distribution-provided wheels. If they want to use virtualenvas  test  suite
     for validation, they should also provide the BUNDLE_FOLDER, BUNDLE_SUPPORT,
     and MAX variables.

     Distributions  should also consider patching virtualenv.seed.embed.base_em-
     bed.PERIODIC_UPDATE_ON_BY_DEFAULT to False,  allowing  the  system  package
     manager  to  control seed package updates rather than virtualenvas periodic
     update mechanism. Users can  still  manually  request  upgrades  via  --up-
     grade-embed-wheels,  but automatic updates wonat interfere with system-man-
     aged packages.

   Activators
     Activation scripts modify the current shell environment to  prioritize  the
     virtual environmentas executables. This is purely a convenience mechanism -
     you  can always use absolute paths to virtual environment executables with-
     out activating.

     What activation does: [graph].INDENT 0.0

     PATH modification
	    The activation script prepends the virtual environmentas bin  direc-
	    tory (Scripts on Windows) to the PATH environment variable. This en-
	    sures that when you run python, pip, or other executables, the shell
	    finds the virtual environmentas versions first.

     Environment variables
	    Activation sets several environment variables:

	    * VIRTUAL_ENV - Absolute path to the virtual environment directory.

	    * VIRTUAL_ENV_PROMPT  -  The  prompt prefix (the environment name or
	      custom value from --prompt).

	    * PKG_CONFIG_PATH - Modified to include  the  virtual  environmentas
	      lib/pkgconfig directory.

     Prompt modification
	    By	default,  activation prepends the environment name to your shell
	    prompt, typically shown as (venv) before the  regular  prompt.  This
	    visual indicator helps you remember which environment is active. You
	    can customize this with the --prompt flag when creating the environ-
	    ment,  or  disable	it  entirely  by  setting  the	VIRTUAL_ENV_DIS-
	    ABLE_PROMPT environment variable.

     Deactivation
	    Activation scripts also provide a deactivate command  that	reverses
	    the  changes, restoring your original PATH and removing the environ-
	    ment variables and prompt modifications.

virtualenv provides activation scripts for multiple shells:

     * Bash (activate)

     * Fish (activate.fish)

     * Csh/Tcsh (activate.csh)

     * PowerShell (activate.ps1)

     * Windows Batch (activate.bat)

     * Nushell (activate.nu)

     * Python (activate_this.py) a for programmatic  activation  from  within  a
       running Python process, see Programmatic activation

     NOTE:
	On  Windows  7	and  later, PowerShellas default execution policy is Re-
	stricted, which prevents running the activate.ps1 script. You can  allow
	locally-generated scripts to run by changing the execution policy:

	    Set-ExecutionPolicy RemoteSigned

	Since  virtualenv  generates  activate.ps1 locally for each environment,
	PowerShell considers it a local script rather than a remote one and  al-
	lows execution under the RemoteSigned policy.

     Remember: activation is optional. The following commands are equivalent:

	# With activation
	source venv/bin/activate
	python script.py
	deactivate

	# Without activation
	venv/bin/python script.py

     For  a  deeper  dive  into how activation works under the hood, see Allison
     Kapturas blog post There^as no magic: virtualenv edition, which explains how
     virtualenv uses PATH and PYTHONHOME to isolate virtual environments.

   See also
     * Use virtualenv - Practical guides for common virtualenv tasks.

     * Command line - Complete CLI reference documentation.

   Plugins
     virtualenv can be extended via plugins using Python entry	points.  Plugins
     are  automatically  discovered from the Python environment where virtualenv
     is installed, allowing you to customize how virtual environments  are  cre-
     ated, seeded, and activated.

   Extension points
     virtualenv provides four extension points through entry point groups:

     virtualenv.discovery
	    Python interpreter discovery plugins. These plugins locate and iden-
	    tify  Python interpreters that will be used as the base for creating
	    virtual environments.

     virtualenv.create
	    Virtual environment creator plugins. These plugins handle the actual
	    creation of the virtual environment structure, including copying  or
	    symlinking the Python interpreter and standard library.

     virtualenv.seed
	    Seed  package installer plugins. These plugins install initial pack-
	    ages (like pip, setuptools, wheel) into newly created virtual  envi-
	    ronments.

     virtualenv.activate
	    Shell  activation  script plugins. These plugins generate shell-spe-
	    cific activation scripts that modify the environment to use the vir-
	    tual environment.

     All extension points follow a common pattern: virtualenv  discovers  regis-
     tered entry points, builds CLI options from them, and executes the selected
     implementations during environment creation.

   Your first plugin
     This tutorial walks through creating a simple discovery plugin that locates
     Python interpreters managed by pyenv.

   Create the package structure
     Set up a new Python package with the following structure:

	virtualenv-pyenv/
	aaa pyproject.toml
	aaa src/
	    aaa virtualenv_pyenv/
		aaa __init__.py

   Configure the entry point
     In  pyproject.toml,  declare  your  plugin as an entry point under the vir-
     tualenv.discovery group:

	[project]
	name = "virtualenv-pyenv"
	version = "0.1.0"
	dependencies = ["virtualenv>=20"]

	[project.entry-points."virtualenv.discovery"]
	pyenv = "virtualenv_pyenv:PyEnvDiscovery"

	[build-system]
	requires = ["setuptools>=61"]
	build-backend = "setuptools.build_meta"

   Implement the plugin
     In src/virtualenv_pyenv/__init__.py, implement the discovery plugin by sub-
     classing Discover:

	from __future__ import annotations

	import subprocess
	from pathlib import Path

	from virtualenv.discovery.discover import Discover
	from virtualenv.discovery.py_info import PythonInfo

	class PyEnvDiscovery(Discover):
	    def __init__(self, options):
		super().__init__(options)
		self.python_spec = options.python if options.python else "python"

	    @classmethod
	    def add_parser_arguments(cls, parser):
		parser.add_argument(
		    "--python",
		    dest="python",
		    metavar="py",
		    type=str,
		    default=None,
		    help="pyenv Python version to use (e.g., 3.11.0)",
		)

	    def run(self):
		try:
		    result = subprocess.run(
			["pyenv", "which", "python"],
			capture_output=True,
			text=True,
			check=True,
		    )
		    python_path = Path(result.stdout.strip())
		    return PythonInfo.from_exe(str(python_path))
		except (subprocess.CalledProcessError, FileNotFoundError) as e:
		    raise RuntimeError(f"Failed to locate pyenv Python: {e}")

   Install the plugin
     Install your plugin in development mode alongside virtualenv:

	$ pip install -e virtualenv-pyenv/

   Verify the plugin
     Check that virtualenv recognizes your plugin by running:

	$ virtualenv --discovery help

     The output should list pyenv as an available discovery mechanism.	You  can
     now use it:

	$ virtualenv --discovery=pyenv myenv
	created virtual environment CPython3.11.0.final.0-64 in 234ms
	  creator CPython3Posix(dest=/path/to/myenv, clear=False, no_vcs_ignore=False, global=False)
	  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/path)
	    added seed packages: pip==23.0, setuptools==65.5.0, wheel==0.38.4
	  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

   Plugin how-to guides
     This  page  provides  task-oriented  guides  for creating each type of vir-
     tualenv plugin.

   Create a discovery plugin
     Discovery plugins locate Python interpreters. Register  your  plugin  under
     the virtualenv.discovery entry point group.

     Implement the Discover interface:

	from virtualenv.discovery.discover import Discover
	from virtualenv.discovery.py_info import PythonInfo

	class CustomDiscovery(Discover):
	    @classmethod
	    def add_parser_arguments(cls, parser):
		parser.add_argument("--custom-opt", help="custom discovery option")

	    def __init__(self, options):
		super().__init__(options)
		self.custom_opt = options.custom_opt

	    def run(self):
		# Locate Python interpreter and return PythonInfo
		python_exe = self._find_python()
		return PythonInfo.from_exe(str(python_exe))

	    def _find_python(self):
		# Implementation-specific logic
		pass

     Register the entry point:

	[virtualenv.discovery]
	custom = your_package.discovery:CustomDiscovery

   Create a creator plugin
     Creator  plugins  build  the  virtual environment structure. Register under
     virtualenv.create.

     Implement the Creator interface:

	from virtualenv.create.creator import Creator

	class CustomCreator(Creator):
	    @classmethod
	    def add_parser_arguments(cls, parser, interpreter):
		parser.add_argument("--custom-creator-opt", help="custom creator option")

	    def __init__(self, options, interpreter):
		super().__init__(options, interpreter)
		self.custom_opt = options.custom_creator_opt

	    def create(self):
		# Create directory structure
		self.bin_dir.mkdir(parents=True, exist_ok=True)
		# Copy or symlink Python executable
		self.install_python()
		# Set up site-packages
		self.install_site_packages()
		# Write pyvenv.cfg
		self.set_pyenv_cfg()

     Register the entry point using a naming pattern that matches  platform  and
     Python version:

	[virtualenv.create]
	cpython3-posix = virtualenv.create.via_global_ref.builtin.cpython.cpython3:CPython3Posix
	cpython3-win = virtualenv.create.via_global_ref.builtin.cpython.cpython3:CPython3Windows

   Create a seeder plugin
     Seeder  plugins install initial packages into the virtual environment. Reg-
     ister under virtualenv.seed.

     Implement the Seeder interface:

	from virtualenv.seed.seeder import Seeder

	class CustomSeeder(Seeder):
	    @classmethod
	    def add_parser_arguments(cls, parser, interpreter, app_data):
		parser.add_argument("--custom-seed-opt", help="custom seeder option")

	    def __init__(self, options, enabled, app_data):
		super().__init__(options, enabled, app_data)
		self.custom_opt = options.custom_seed_opt

	    def run(self, creator):
		# Install packages into creator.bin_dir / creator.script("pip")
		self._install_packages(creator)

	    def _install_packages(self, creator):
		# Implementation-specific logic
		pass

     Register the entry point:

	[virtualenv.seed]
	custom = your_package.seed:CustomSeeder

   Create an activator plugin
     Activator plugins generate shell activation scripts.  Register  under  vir-
     tualenv.activate.

     Implement the Activator interface:

	from virtualenv.activation.activator import Activator

	class CustomShellActivator(Activator):
	    def generate(self, creator):
		# Generate activation script content
		script_content = self._render_template(creator)
		# Write to activation directory
		dest = creator.bin_dir / self.script_name
		dest.write_text(script_content)

	    def _render_template(self, creator):
		# Return activation script content
		return f"""
		# Custom shell activation script
		export VIRTUAL_ENV="{creator.dest}"
		export PATH="{creator.bin_dir}:$PATH"
		"""

	    @property
	    def script_name(self):
		return "activate.custom"

     Register the entry point:

	[virtualenv.activate]
	bash = virtualenv.activation.bash:BashActivator
	fish = virtualenv.activation.fish:FishActivator
	custom = your_package.activation:CustomShellActivator

   Package and distribute a plugin
     Use pyproject.toml to declare entry points:

	[project]
	name = "virtualenv-custom-plugin"
	version = "1.0.0"
	dependencies = ["virtualenv>=20.0.0"]

	[project.entry-points."virtualenv.discovery"]
	custom = "virtualenv_custom.discovery:CustomDiscovery"

	[project.entry-points."virtualenv.create"]
	custom-posix = "virtualenv_custom.creator:CustomCreator"

	[project.entry-points."virtualenv.seed"]
	custom = "virtualenv_custom.seeder:CustomSeeder"

	[project.entry-points."virtualenv.activate"]
	custom = "virtualenv_custom.activator:CustomActivator"

	[build-system]
	requires = ["setuptools>=61"]
	build-backend = "setuptools.build_meta"

     Install your plugin alongside virtualenv:

	$ pip install virtualenv-custom-plugin

     Or in development mode:

	$ pip install -e /path/to/virtualenv-custom-plugin

     Test your plugin by creating a virtual environment:

	$ virtualenv --discovery=custom --creator=custom-posix --seeder=custom --activators=custom test-env

   Plugin API reference
     This page documents the interfaces that plugins must implement.

   Discovery
     Discovery	plugins locate Python interpreters for creating virtual environ-
     ments.

     class virtualenv.discovery.discover.Discover(options)

	    Parameters
		   options (VirtualEnvOptions)

	    classmethod add_parser_arguments(parser)

		   Parameters
			  parser (ArgumentParser)

		   Return type
			  None

	    abstractmethod run()

		   Return type
			  Optional[PythonInfo]

	    property interpreter: PythonInfo | None

		   Returns
			  the interpreter as returned by run(), cached

   PythonInfo
     Discovery plugins return a PythonInfo object describing the located  inter-
     preter.

     class virtualenv.discovery.py_info.PythonInfo
	    Contains information for a Python interpreter.

	    install_path(key)
		   Return  the	relative installation path for a given installa-
		   tion scheme key.

		   Parameters
			  key (str) -- sysconfig installation scheme  key  (e.g.
			  "scripts", "purelib").

		   Return type
			  str

	    property version_str: str
		   The full version as major.minor.micro string (e.g. 3.13.2).

	    property version_release_str: str
		   The release version as major.minor string (e.g. 3.13).

	    property python_name: str
		   The python executable name as pythonX.Y (e.g. python3.13).

	    property is_old_virtualenv: bool
		   True  if this interpreter runs inside an old-style virtualenv
		   (has real_prefix).

	    property is_venv: bool
		   True if this interpreter runs inside  a  PEP  405  venv  (has
		   base_prefix).

	    sysconfig_path(key, config_var=None, sep='/')
		   Return  the	sysconfig install path for a scheme key, option-
		   ally substituting config variables.

		   Parameters

			  * key (str) -- sysconfig  path  key  (e.g.  "purelib",
			    "include").

			  * config_var (Optional[dict[str, str]]) -- replacement
			    mapping  for sysconfig variables; when None uses the
			    interpreter's own values.

			  * sep (str) -- path separator to use in the result.

		   Return type
			  str

	    property system_include: str
		   The path to the system include directory for C headers.

	    property system_prefix: str
		   The prefix of the system Python this interpreter is based on.

	    property system_exec_prefix: str
		   The exec prefix of the  system  Python  this  interpreter  is
		   based on.

	    property machine: str
		   Return  the	instruction  set architecture (ISA) derived from
		   sysconfig.get_platform().

	    property spec: str
		   A specification string  identifying	this  interpreter  (e.g.
		   CPython3.13.2-64-arm64).

	    classmethod clear_cache(cache)
		   Clear all cached interpreter information from cache.

		   Parameters
			  cache (PyInfoCache) -- the cache store to clear.

		   Return type
			  None

	    satisfies(spec, *, impl_must_match)
		   Check  if  a  given	specification  can  be satisfied by this
		   python interpreter instance.

		   Parameters

			  * spec (PythonSpec)  --  the	specification  to  check
			    against.

			  * impl_must_match (bool) -- when True, the implementa-
			    tion name must match exactly.

		   Return type
			  bool

	    classmethod current(cache=None)
		   Locate the current host interpreter information.

		   Parameters
			  cache  (PyInfoCache  |  None)  -- interpreter metadata
			  cache; when None results are not cached.

		   Return type
			  PythonInfo

	    classmethod current_system(cache=None)
		   Locate the current system interpreter information,  resolving
		   through any virtualenv layers.

		   Parameters
			  cache  (PyInfoCache  |  None)  -- interpreter metadata
			  cache; when None results are not cached.

		   Return type
			  PythonInfo

	    to_json()
		   Serialize this interpreter information to a JSON string.

		   Return type
			  str

	    to_dict()
		   Convert this interpreter information to a plain dictionary.

		   Return type
			  dict[str, object]

	    classmethod from_exe(exe, cache=None, *, raise_on_error=True, ig-
	    nore_cache=False, resolve_to_host=True, env=None)
		   Get the python information for a given executable path.

		   Parameters

			  * exe (str) -- path to the Python executable.

			  * cache (PyInfoCache | None) --  interpreter	metadata
			    cache; when None results are not cached.

			  * raise_on_error (bool) -- raise on failure instead of
			    returning None.

			  * ignore_cache (bool) -- bypass the cache and re-query
			    the interpreter.

			  * resolve_to_host (bool) -- resolve through virtualenv
			    layers to the system interpreter.

			  * env  (Mapping[str,	str] | None) -- environment map-
			    ping; defaults to os.environ.

		   Return type
			  PythonInfo | None

	    classmethod from_json(payload)
		   Deserialize interpreter information from a JSON string.

		   Parameters
			  payload (str) -- JSON produced by to_json().

		   Return type
			  PythonInfo

	    classmethod from_dict(data)
		   Reconstruct a PythonInfo from a plain dictionary.

		   Parameters
			  data (dict[str, object])  --	dictionary  produced  by
			  to_dict().

		   Return type
			  PythonInfo

	    classmethod resolve_to_system(cache, target)
		   Walk  virtualenv/venv  prefix  chains  to find the underlying
		   system interpreter.

		   Parameters

			  * cache (PyInfoCache | None) --  interpreter	metadata
			    cache; when None results are not cached.

			  * target (PythonInfo) -- the interpreter to resolve.

		   Return type
			  PythonInfo

	    discover_exe(cache, prefix, *, exact=True, env=None)
		   Discover  a	matching  Python executable under a given prefix
		   directory.

		   Parameters

			  * cache (PyInfoCache) -- interpreter metadata cache.

			  * prefix (str) -- directory prefix to search under.

			  * exact (bool) -- when True, require an exact  version
			    match.

			  * env  (Mapping[str,	str] | None) -- environment map-
			    ping; defaults to os.environ.

		   Return type
			  PythonInfo

   App data
     The application data interface used by plugins for caching.

     class virtualenv.app_data.base.AppData
	    Abstract storage interface for the virtualenv application.

	    abstractmethod close()
		   Called before virtualenv exits.

		   Return type
			  None

	    abstractmethod reset()
		   Called when the user passes in the reset app data.

		   Return type
			  None

	    abstractmethod py_info(path)
		   Return a content store for cached interpreter information  at
		   the given path.

		   Parameters
			  path (Path) -- the interpreter executable path

		   Return type
			  ContentStore

		   Returns
			  a content store for the cached data

	    abstractmethod py_info_clear()
		   Clear all cached interpreter information.

		   Return type
			  None

	    property can_update: bool
		   True if this app data store supports updating cached content.

	    abstractmethod embed_update_log(distribution, for_py_version)
		   Return a content store for the embed update log of a distrib-
		   ution.

		   Parameters

			  * distribution (str) -- the package name (e.g. pip)

			  * for_py_version  (str)  --  the target Python version
			    string

		   Return type
			  ContentStore

		   Returns
			  a content store for the update log

	    property house: Path
		   The root directory of the application data store.

	    property transient: bool
		   True if this app data store is transient and does not persist
		   across runs.

	    abstractmethod wheel_image(for_py_version, name)
		   Return the path to a cached wheel image.

		   Parameters

			  * for_py_version (str) -- the  target  Python  version
			    string

			  * name (str) -- the package name

		   Return type
			  Path

		   Returns
			  the path to the cached wheel

	    ensure_extracted(path, to_folder=None)
		   Ensure a path is available on disk, extracting from zipapp if
		   needed.

		   Parameters

			  * path (Path) -- the path to ensure is available

			  * to_folder (Optional[Path]) -- optional target direc-
			    tory for extraction

		   Return type
			  Generator[Path]

		   Returns
			  yields the usable path on disk

	    abstractmethod extract(path, to_folder)
		   Extract a path from the zipapp to a location on disk.

		   Parameters

			  * path (Path) -- the path to extract

			  * to_folder (Optional[Path]) -- optional target direc-
			    tory

		   Return type
			  Generator[Path]

		   Returns
			  yields the extracted path

	    abstractmethod locked(path)
		   Acquire an exclusive lock on the given path.

		   Parameters
			  path (Path) -- the path to lock

		   Return type
			  Generator[None]

   Creators
     Creator  plugins  build the virtual environment directory structure and in-
     stall the Python interpreter.

     class virtualenv.create.creator.CreatorMeta

     class virtualenv.create.creator.Creator(options, interpreter)
	    A class that given a python Interpreter creates a  virtual	environ-
	    ment.

	    Parameters

		   * options (VirtualEnvOptions)

		   * interpreter (PythonInfo)

	    Construct a new virtual environment creator.

	    Parameters

		   * options  (VirtualEnvOptions)  --  the  CLI option as parsed
		     from add_parser_arguments()

		   * interpreter (PythonInfo) -- the interpreter to create  vir-
		     tual environment from

	    classmethod can_create(interpreter)
		   Determine if we can create a virtual environment.

		   Parameters
			  interpreter  (PythonInfo)  -- the interpreter in ques-
			  tion

		   Return type
			  UnionType[CreatorMeta, bool, None]

		   Returns
			  None if we can't create, any	other  object  otherwise
			  that will be forwarded to add_parser_arguments()

	    classmethod add_parser_arguments(parser, interpreter, meta,
	    app_data)
		   Add CLI arguments for the creator.

		   Parameters

			  * parser (ArgumentParser) -- the CLI parser

			  * app_data (AppData) -- the application data folder

			  * interpreter  (PythonInfo)  --  the interpreter we're
			    asked to create virtual environment for

			  * meta  (CreatorMeta)  --   value   as   returned   by
			    can_create()

		   Return type
			  None

	    abstractmethod create()
		   Perform the virtual environment creation.

		   Return type
			  None

	    add_cachedir_tag()
		   Generate  a	file  indicating  that	this  is not meant to be
		   backed up.

		   Return type
			  None

	    setup_ignore_vcs()
		   Generate ignore instructions for version control systems.

		   Return type
			  None

   Seeders
     Seeder plugins install initial packages (like pip, setuptools, wheel)  into
     the virtual environment.

     class virtualenv.seed.seeder.Seeder(options, enabled)
	    A seeder will install some seed packages into a virtual environment.

	    Parameters

		   * options (VirtualEnvOptions)

		   * enabled (bool)

	    Create.

	    Parameters

		   * options  (VirtualEnvOptions)  --  the parsed options as de-
		     fined within add_parser_arguments()

		   * enabled (bool) -- a flag weather the seeder is  enabled  or
		     not

	    classmethod add_parser_arguments(parser, interpreter, app_data)
		   Add CLI arguments for this seed mechanisms.

		   Parameters

			  * parser (ArgumentParser) -- the CLI parser

			  * app_data (AppData) -- the CLI parser

			  * interpreter  (PythonInfo)  --  the	interpreter this
			    virtual environment is based of

		   Return type
			  None

	    abstractmethod run(creator)
		   Perform the seed operation.

		   Parameters
			  creator   (Creator)	--   the   creator   (based   of
			  virtualenv.create.creator.Creator)  we  used to create
			  this virtual environment

		   Return type
			  None

   Activators
     Activator plugins generate shell-specific activation scripts.

     class virtualenv.activation.activator.Activator(options)
	    Generates activate script for the virtual environment.

	    Parameters
		   options (VirtualEnvOptions)

	    Create a new activator generator.

	    Parameters
		   options (VirtualEnvOptions) -- the parsed options as  defined
		   within add_parser_arguments()

	    classmethod supports(interpreter)
		   Check  if the activation script is supported in the given in-
		   terpreter.

		   Parameters
			  interpreter (PythonInfo) -- the interpreter we need to
			  support

		   Return type
			  bool

		   Returns
			  True if supported, False otherwise

	    classmethod add_parser_arguments(parser, interpreter)
		   Add CLI arguments for this activation script.

		   Parameters

			  * parser (ArgumentParser) -- the CLI parser

			  * interpreter (PythonInfo)  --  the  interpreter  this
			    virtual environment is based of

		   Return type
			  None

	    abstractmethod generate(creator)
		   Generate activate script for the given creator.

		   Parameters
			  creator   (Creator)	--   the   creator   (based   of
			  virtualenv.create.creator.Creator) we used  to  create
			  this virtual environment

		   Return type
			  list[Path]

   Plugin architecture
     This page explains how virtualenvas plugin system works internally.

   Entry points
     virtualenv  uses  Python  entry points (setuptools / importlib.metadata) to
     discover plugins. Each plugin registers  under  one  of  four  entry  point
     groups:

     * virtualenv.discovery

     * virtualenv.create

     * virtualenv.seed

     * virtualenv.activate

     At  startup, virtualenv loads all registered entry points from these groups
     and makes them available as CLI options.  Built-in implementations are reg-
     istered in virtualenvas own pyproject.toml, while third-party plugins  reg-
     ister their entry points in their own package metadata.

     When a package with virtualenv plugins is installed in the same environment
     as  virtualenv, the plugins become immediately available without additional
     configuration.

   Plugin lifecycle
     The following diagram  shows  how	plugins  are  discovered  and  executed:
     [graph]

     The lifecycle follows these stages:

     1. virtualenv  starts  and  discovers all entry points from the four plugin
	groups

     2. The CLI parser is built dynamically, incorporating options from all dis-
	covered plugins

     3. User arguments are parsed to select which  discovery,  creator,  seeder,
	and activator plugins to use

     4. Selected  plugins  execute in sequence: discover a create a seed a acti-
	vate

     5. Each stage passes its output to the next stage

   Extension point design
     Each extension point follows a consistent pattern:

     Base abstract class
	    Each extension point defines a base abstract class	(Discover,  Cre-
	    ator,  Seeder,  Activator) that specifies the interface plugins must
	    implement.

     Built-in implementations
	    virtualenv includes built-in  implementations  registered  as  entry
	    points  in its own pyproject.toml. For example, the built-in CPython
	    creator is registered as cpython3-posix.

     Third-party plugins
	    External packages implement the base interface  and  register  their
	    own  entry	points under the same group. When installed, they appear
	    alongside built-in options.

     CLI selection
	    Command-line flags (--discovery, --creator, --seeder,  --activators)
	    allow  users to select which implementation to use. Multiple activa-
	    tors can be selected simultaneously.

     Parser integration
	    Each plugin can contribute CLI arguments through the  add_parser_ar-
	    guments classmethod. These arguments appear in virtualenv --help and
	    are available when the plugin is selected.

   How plugins interact
     Plugins execute in a pipeline where each stage depends on the previous one:

     Discovery ^a Creator
	    The  discovery  plugin  produces  a PythonInfo object describing the
	    source Python interpreter. This object contains metadata  about  the
	    Python  version, platform, paths, and capabilities. The creator plu-
	    gin receives this PythonInfo and uses it to determine how  to  build
	    the virtual environment structure.

     Creator ^a Seeder
	    The  creator plugin produces a Creator object representing the newly
	    created virtual environment. This includes paths to the  environmen-
	    tas  bin directory, site-packages, and Python executable. The seeder
	    plugin uses these paths to install packages.

     Seeder ^a Activator
	    After seeding completes, activator plugins use the Creator object to
	    generate shell activation scripts. These scripts reference the envi-
	    ronmentas bin directory and other paths to configure the shell envi-
	    ronment.

     This pipeline ensures that each plugin has the information  it  needs  from
     previous  stages.	The  PythonInfo flows from discovery to creator, and the
     Creator object flows from creator to both seeder and activators.

   Plugin isolation
     Plugins within the same extension point do not interact  with  each  other.
     Only  one	discovery  and one creator plugin can run per invocation, though
     multiple activators can run simultaneously. This  isolation  keeps  plugins
     simple and focused on their specific task.

   Development
   Getting started
     virtualenv  is  a	volunteer  maintained open source project and we welcome
     contributions of all forms. The sections below will help  you  get  started
     with  development,  testing,  and documentation. Weare pleased that you are
     interested in working on virtualenv. This document  is  meant  to	get  you
     setup  to work on virtualenv and to act as a guide and reference to the de-
     velopment setup. If you face any issues during this process, please open an
     issue about it on the issue tracker.

   Setup
     virtualenv is a command line application written in Python. To work on  it,
     youall need:

     *

       Source code: available on GitHub. You can use git to clone the
	      repository:

	  git clone https://github.com/pypa/virtualenv
	  cd virtualenv

     * Python interpreter: We recommend using CPython. You can use this guide to
       set it up.

     * tox:  to  automatically get the projects development dependencies and run
       the test suite. We recommend installing it using pipx.

   Running from source tree
     The easiest way to do this is to generate the development tox  environment,
     and then invoke virtualenv from under the .tox/dev folder

	tox -e dev
	.tox/dev/bin/virtualenv  # on Linux
	.tox/dev/Scripts/virtualenv  # on Windows

   Running tests
     virtualenvas tests are written using the pytest test framework. tox is used
     to automate the setup and execution of virtualenvas tests.

     To run tests locally execute:

	tox -e py

     This will run the test suite for the same Python version as under which tox
     is installed. Alternatively you can specify a specific version of python by
     using the pyNN format, such as: py38, pypy3, etc.

     tox  has been configured to forward any additional arguments it is given to
     pytest. This enables the use of pytestas rich CLI. As an example,	you  can
     select tests using the various ways that pytest provides:

	# Using markers
	tox -e py -- -m "not slow"
	# Using keywords
	tox -e py -- -k "test_extra"

     Some  tests  require additional dependencies to be run, such is the various
     shell activators (bash, fish, powershell, etc). These tests will  automati-
     cally  be	skipped  if  these  are not present, note however that in CI all
     tests are run; so even if all tests succeed locally for you, they may still
     fail in the CI.

   Running linters
     virtualenv uses pre-commit for managing linting of the codebase. pre-commit
     performs various checks on all files in virtualenv and uses tools that help
     follow a consistent code style within the codebase. To use linters locally,
     run:

	tox -e fix

     NOTE:
	Avoid using # noqa comments to suppress linter warnings - wherever  pos-
	sible,	warnings  should be fixed instead.  # noqa comments are reserved
	for rare cases where the recommended  style  causes  severe  readability
	problems.

   Type checking
     virtualenv ships a PEP 561 py.typed marker and has comprehensive type anno-
     tations  across  the  entire codebase.  This means downstream consumers and
     type checkers automatically recognize virtualenv as an  inline-typed  pack-
     age.

     All new code must include complete type annotations for function parameters
     and return types. To verify annotations locally, run:

	tox -e type

     This  uses  ty  (Astralas	Rust-based type checker) to validate annotations
     against Python 3.14. A second environment	checks	compatibility  with  the
     minimum supported version:

	tox -e type-3.8

     Both environments validate that annotations are consistent and correct.

   Annotation guidelines
     * Use  from  __future__  import annotations at the top of every module (en-
       forced by ruffas required-imports setting).

     * Place imports that are  only  needed  for  type	checking  inside  an  if
       TYPE_CHECKING: block to avoid runtime overhead.

     * Ruffas  ANN  rules  are	enabled.  ANN401 (typing.Any) is suppressed on a
       case-by-case basis with inline # noqa: ANN401 comments where Any is  gen-
       uinely required (e.g. serialization, dynamic dispatch).

     * Prefer  concrete types over Any. Use Union / | for nullable or multi-type
       parameters.

     * When a type error is genuinely unfixable (e.g. third-party library  limi-
       tations),  suppress it with an inline # ty: ignore[rule-name] comment and
       a brief justification.

   Building documentation
     virtualenvas documentation is built  using  Sphinx.  The  documentation  is
     written in reStructuredText. To build it locally, run:

	tox -e docs

     The built documentation can be found in the .tox/docs_out folder and may be
     viewed by opening index.html within that folder.

   Release
     virtualenvas  release schedule is tied to pip and setuptools. We bundle the
     latest version of these libraries so each time thereas a new version of any
     of these, there will be a new virtualenv  release	shortly  afterwards  (we
     usually wait just a few days to avoid pulling in any broken releases).

   Performing a release
     A	full release publishes to PyPI, creates a GitHub Release with the zipapp
     attached, and updates get-virtualenv so that https://bootstrap.pypa.io/vir-
     tualenv.pyz serves the new version.

   Version bumping
     The --version argument to tox r -e release controls  the  version.  It  de-
     faults  to auto, which inspects the docs/changelog directory: if any *.fea-
     ture.rst or *.removal.rst fragments exist, the  minor  version  is  bumped,
     otherwise	the  patch version is bumped. You can also pass major, minor, or
     patch explicitly.

     Both methods produce identical results: a release commit and tag  on  main.
     Pushing  the  tag	triggers  the  Release	workflow which builds the sdist,
     wheel, and zipapp, publishes to PyPI via trusted  publisher,  creates  a  -
     GitHub  Release  with  the  zipapp attached, and updates get-virtualenv. If
     publish fails, a rollback job automatically reverts everything.

     Via GitHub Actions (recommended)

     1. Go to the Pre-release workflow on GitHub.

     2. Click Run workflow and select the bump	type  (auto,  major,  minor,  or
	patch).

     Locally

	tox r -e release

     Pass --version <bump> to override the default auto behavior (e.g. --version
     minor).

   Contributing
   Submitting pull requests
     Submit  pull requests against the main branch, providing a good description
     of what youare doing and why. You must have legal permission to  distribute
     any  code	you  contribute to virtualenv and it must be available under the
     MIT License. Provide tests that cover your changes and run  the  tests  lo-
     cally  first.  virtualenv	supports  multiple Python versions and operating
     systems. Any pull request must consider and work on all these platforms.

     Pull Requests should be small to facilitate  review.  Keep  them  self-con-
     tained,  and limited in scope. Studies have shown that review quality falls
     off as patch size grows. Sometimes this will result in many  small  PRs  to
     land  a  single  large  feature.  In  particular, pull requests must not be
     treated as afeature branchesa,  with  ongoing  development  work  happening
     within the PR. Instead, the feature should be broken up into smaller, inde-
     pendent parts which can be reviewed and merged individually.

     Additionally,  avoid including acosmetica changes to code that is unrelated
     to your change, as these make reviewing the PR more difficult. Examples in-
     clude re-flowing text in comments or documentation, or addition or  removal
     of  blank	lines or whitespace within lines. Such changes can be made sepa-
     rately, as a aformatting cleanupa PR, if needed.

   Automated testing
     All pull requests and merges to amaina branch are tested using  GitHub  Ac-
     tions  (configured  by .github/workflows/check.yaml file at the root of the
     repository). You can find the status and results to the CI runs for your PR
     on GitHubas Web UI for the pull request. You can also find links to the  CI
     servicesa	pages for the specific builds in the form of aDetailsa links, in
     case the CI run fails and you wish to view the output.

     To trigger CI to run again for a pull request, you can close and  open  the
     pull  request  or	submit	another  change  to the pull request. If needed,
     project maintainers can manually trigger a restart of a job/build.

   NEWS entries
     The changelog.rst file is managed	using  towncrier  and  all  non  trivial
     changes  must  be	accompanied by a news entry. To add an entry to the news
     file, first you need to have created an issue  describing	the  change  you
     want  to  make.  A Pull Request itself may function as such, but it is pre-
     ferred to have a dedicated issue (for example, in case the PR ends  up  re-
     jected due to code quality reasons).

     Once  you have an issue or pull request, you take the number and you create
     a file inside of the docs/changelog directory named after that issue number
     with an extension of:

     * feature.rst,

     * bugfix.rst,

     * doc.rst,

     * removal.rst,

     * misc.rst.

     Thus if your issue or PR number is 1234 and this change is  fixing  a  bug,
     then  you	would create a file docs/changelog/1234.bugfix.rst. PRs can span
     multiple categories by creating multiple files (for instance, if you  added
     a	feature  and  deprecated/removed  the  old feature at the same time, you
     would  create  docs/changelog/1234.bugfix.rst  and  docs/changelog/1234.re-
     move.rst).  Likewise  if  a PR touches multiple issues/PRs you may create a
     file for each of them with the same contents and towncrier will deduplicate
     them.

   Contents of a NEWS entry
     The contents of this file are reStructuredText formatted text that will  be
     used  as  the content of the news file entry.  You do not need to reference
     the issue or PR numbers here as towncrier will automatically add  a  refer-
     ence to all of the affected issues when rendering the news file.

     In  order	to  maintain a consistent style in the changelog.rst file, it is
     preferred to keep the news entry to the point, in	sentence  case,  shorter
     than  120	characters  and in an imperative tone a an entry should complete
     the sentence This change will ^a|. In rare cases,  where  one  line  is  not
     enough,  use  a summary line in an imperative tone followed by a blank line
     separating it from a description of the feature/change in one or more para-
     graphs, each wrapped at 120 characters. Remember that a news entry is meant
     for end users and should only contain details relevant to an end user.

   Choosing the type of NEWS entry
     A trivial change is anything that does not warrant an  entry  in  the  news
     file.  Some  examples are: code refactors that donat change anything as far
     as the public is concerned, typo fixes, white space modification,	etc.  To
     mark  a  PR  as trivial a contributor simply needs to add a randomly named,
     empty file to the news/ directory with the extension of .trivial.

   Becoming a maintainer
     If you want to become an official maintainer, start by helping  out.  As  a
     first  step, we welcome you to triage issues on virtualenvas issue tracker.
     virtualenv maintainers provide triage abilities to contributors  once  they
     have  been  around for some time and contributed positively to the project.
     This is optional and highly recommended for  becoming  a  virtualenv  main-
     tainer.  Later,  when  you think youare ready, get in touch with one of the
     maintainers and they will initiate a vote among the existing maintainers.

     NOTE:
	Upon becoming a maintainer, a person should be given access  to  various
	virtualenv-related  tooling  across  multiple platforms. These are noted
	here for future reference by the maintainers:

	* GitHub Push Access

	* PyPI Publishing Access

	* CI Administration capabilities

	* ReadTheDocs Administration capabilities

   Current maintainers
     * Bern~A!t G~A!bor

     * Rahul Devikar

   Previous maintainers
     * Paul Moore

     * Ian Bicking

     * Donald Stufft

   Release History
   v[UNRELEASED DRAFT] (2026-08-27)
     No significant changes.

   v21.2.3 (2026-04-14)
     No significant changes.

   v21.2.2 (2026-04-13)
   Bugfixes - 21.2.2
     * Bump python-discovery minimum to >=1.2.2 to include normalize_isa support
       - by @rahuldevikar.  (#3117)

   v21.2.1 (2026-04-09)
   Bugfixes - 21.2.1
     * Upgrade embedded wheels:

       * setuptools to 82.0.1 from 82.0.0 (#3093)

     * Use terminal width for help formatting instead of hardcoded 240. (#3110)

   v21.2.0 (2026-03-09)
   Features - 21.2.0
     * Update embed wheel generator (tasks/upgrade_wheels.py)  to  include  type
       annotations in generated output - by @rahuldevikar. (#3075)

   Bugfixes - 21.2.0
     * Pass  --without-scm-ignore-files  to  subprocess  venv on Python 3.13+ so
       virtualenv controls .gitignore creation, fixing flaky test_create_no_seed
       and --no-vcs-ignore being ignored in subprocess path -  by  @gaborbernat.
       (#3089)

     * Use  BASH_SOURCE[0]  instead of $0 in the bash activate script relocation
       fallback, fixing incorrect PATH when sourcing the activate script from  a
       different directory - by @gaborbernat. (#3090)

   v21.1.0 (2026-02-27)
   Features - 21.1.0
     * Add  comprehensive type annotations across the entire codebase and ship a
       PEP 561 py.typed marker so downstream consumers and type checkers  recog-
       nize virtualenv as an inline-typed package - by @rahuldevikar. (#3075)

   v21.0.0 (2026-02-25)
   Deprecations and Removals - 21.0.0
     * The   Python  discovery	logic  has  been  extracted  into  a  standalone
       python-discovery package on PyPI (documentation) and is now consumed as a
       dependency. If you previously imported discovery internals directly (e.g.
       from virtualenv.discovery.py_info  import  PythonInfo),	switch	to  from
       python_discovery   import  PythonInfo.  Backward-compatibility  re-export
       shims are provided  at  virtualenv.discovery.py_info,  virtualenv.discov-
       ery.py_spec,  and  virtualenv.discovery.cached_py_info, however these are
       considered unsupported and may be removed in a  future  release	-  by  -
       @gaborbernat.  (#3070)

   v20.39.1 (2026-02-25)
   Features - 20.39.1
     * Add  support  for  creating  virtual  environments with RustPython - by -
       @elmjag. (#3010)

   v20.39.0 (2026-02-23)
   Features - 20.39.0
     * Automatically resolve version manager shims (pyenv, mise,  asdf)  to  the
       real Python binary during discovery, preventing incorrect interpreter se-
       lection when shims are on PATH - by @gaborbernat. (#3049)

     * Add  architecture  (ISA)  awareness  to	Python discovery a users can now
       specify a CPU architecture suffix  in  the  --python  spec  string  (e.g.
       cpython3.12-64-arm64)  to distinguish between interpreters that share the
       same version and bitness but target different architectures. Uses syscon-
       fig.get_platform() as the data source, with cross-platform  normalization
       (amd64 a x86_64, aarch64 a arm64). Omitting the suffix preserves existing
       behavior - by @rahuldevikar. (#3059)

   v20.38.0 (2026-02-19)
   Features - 20.38.0
     * Store app data (pip/setuptools/wheel caches) under the OS cache directory
       (platformdirs.user_cache_dir)  instead  of  the	data directory (platfor-
       mdirs.user_data_dir). Existing app data at the old location is  automati-
       cally  migrated	on  first use. This ensures cached files that can be re-
       downloaded are placed in the standard cache location (e.g.   ~/.cache  on
       Linux,  ~/Library/Caches  on  macOS) where they are excluded from backups
       and can be cleaned by system tools - by @rahuldevikar. (#1884) (#1884)

     * Add  PKG_CONFIG_PATH  environment  variable  support  to  all  activation
       scripts	(Bash,	Batch,	PowerShell, Fish, C Shell, Nushell, and Python).
       The virtualenvas lib/pkgconfig directory is now	automatically  prepended
       to  PKG_CONFIG_PATH  on activation and restored on deactivation, enabling
       packages that use pkg-config during build/install to find their	configu-
       ration files - by @rahuldevikar. (#2637)

     * Upgrade embedded pip to 26.0.1 from 25.3 and setuptools to 82.0.0, 75.3.4
       from 75.3.2, 80.9.0 - by @rahuldevikar. (#3027)

     * Replace	ty:  ignore comments with proper type narrowing using assertions
       and explicit None checks - by @rahuldevikar. (#3029)

   Bugfixes - 20.38.0
     * Exclude pywin32 DLLs (pywintypes*.dll, pythoncom*.dll) from being  copied
       to  the	Scripts  directory  during  virtualenv creation on Windows. This
       fixes compatibility issues with pywin32, which expects its DLLs to be in-
       stalled in site-packages/pywin32_system32 by its own post-install  script
       - by @rahuldevikar. (#2662)

     * Preserve  symlinks  in  pyvenv.cfg  paths  to  match  venv  behavior. Use
       os.path.abspath() instead of os.path.realpath() to normalize paths  with-
       out  resolving symlinks, fixing issues with Python installations accessed
       via symlinked directories (common in network-mounted filesystems) - by  -
       @rahuldevikar. Fixes #2770.  (#2770)

     * Fix  Windows  activation  scripts to properly quote python.exe path, pre-
       venting failures when Python is installed in a path  with  spaces  (e.g.,
       C:\Program  Files) and a file named C:\Program exists on the filesystem -
       by @rahuldevikar. (#2985)

     * Fix bash -u (set -o nounset) compatibility in bash activation  script  by
       using ${PKG_CONFIG_PATH:-} and ${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}} to
       handle unset PKG_CONFIG_PATH - by @Fridayai700.	(#3044)

     * Gracefully  handle  corrupted  on-disk cache and invalid JSON from Python
       interrogation subprocess instead of crashing with unhandled JSONDecodeEr-
       ror or KeyError - by @gaborbernat. (#3054)

   v20.36.1 (2026-01-09)
   Bugfixes - 20.36.1
     * Fix TOCTOU vulnerabilities in app_data and lock directory  creation  that
       could be exploited via symlink attacks - reported by @tsigouris007, fixed
       by @gaborbernat. (#3013)

   v20.36.0 (2026-01-07)
   Features - 20.36.0
     * Add  support  for  PEP 440 version specifiers in the --python flag. Users
       can now specify Python versions using operators like >=, <=, ~=, etc. For
       example: virtualenv --python=">=3.12" myenv . (:issue:`2994)

   v20.35.4 (2025-10-28)
   Bugfixes - 20.35.4
     * Fix race condition in _virtualenv.py when file is overwritten during  im-
       port,  preventing  NameError  when  _DISTUTILS_PATCH  is  accessed - by -
       @gracetyy. (#2969)

     * Upgrade embedded wheels:

       * pip to 25.3 from 25.2 (#2989)

   v20.35.3 (2025-10-10)
   Bugfixes - 20.35.3
     * Accept RuntimeError in test_too_many_open_files, by @esafak (#2935)

   v20.35.2 (2025-10-10)
   Bugfixes - 20.35.2
     * Revert out changes related to the extraction of the discovery module - by
       @gaborbernat. (#2978)

   v20.35.1 (2025-10-09)
   Bugfixes - 20.35.1
     * Patch get_interpreter to handle missing cache and app_data -  by  @esafak
       (#2972)

     * Fix  backwards  incompatible  changes to PythonInfo - by @gaborbernat. (-
       #2975)

   v20.35.0 (2025-10-08)
   Features - 20.35.0
     * Add AppData and Cache protocols to discovery for decoupling - by @esafak.
       (#2074)

     * Ensure python3.exe and python3 on Windows for Python 3 - by  @esafak.  (-
       #2774)

   Bugfixes - 20.35.0
     * Replaced  direct  references  to tcl/tk library paths with getattr - by -
       @esafak (#2944)

     * Restore absolute import of fs_is_case_sensitive - by @esafak. (#2955)

   v20.34.0 (2025-08-13)
   Features - 20.34.0
     * Abstract out caching in discovery - by @esafak. Decouple  FileCache  from
       py_info	(discovery)  - by @esafak. Remove references to py_info in File-
       Cache - by @esafak. Decouple discovery from creator plugins - by @esafak.
       Decouple discovery by duplicating info utils - by @esafak. (#2074)

     * Add PyPy 3.11 support. Contributed by @esafak. (#2932)

   Bugfixes - 20.34.0
     * Upgrade embedded wheel pip to 25.2 from 25.1.1 - by @gaborbernat. (#2333)

     * Accept RuntimeError in test_too_many_open_files, by @esafak (#2935)

     * Python in PATH takes precedence over uv-managed python. Contributed by  -
       @edgarrmondragon. (#2952)

   v20.33.1 (2025-08-05)
   Bugfixes - 20.33.1
     * Correctly  unpack  _get_tcl_tk_libs() response in PythonInfo. Contributed
       by @esafak. (#2930)

     * Restore	  py_info.py	timestamp    in     test_py_info_cache_invalida-
       tion_on_py_info_change Contributed by @esafak.  (#2933)

   v20.33.0 (2025-08-03)
   Features - 20.33.0
     * Added  support  for  Tcl  and  Tkinter.	Youare welcome. Contributed by -
       @esafak. (#425)

   Bugfixes - 20.33.0
     * Prevent logging setup when ahelp is passed, fixing  a  flaky  test.  Con-
       tributed by @esafak. (#u)

     * Fix  cache invalidation for PythonInfo by hashing py_info.py. Contributed
       by @esafak. (#2467)

     * When no discovery plugins are found, the application would crash  with  a
       StopIteration.  This  change  catches the StopIteration and raises a Run-
       timeError with a more informative message. Contributed  by  @esafak.   (-
       #2493)

     * Stop  ^atry-first-with overriding absolute ^apython paths. Contributed by -
       @esafak. (#2659)

     * Force UTF-8 encoding for pip download Contributed by @esafak. (#2780)

     * Creating a virtual environment on a  filesystem	without  symlink-support
       would fail even with ^acopies Make fs_supports_symlink perform a real sym-
       link creation check on all platforms. Contributed by @esafak.  (#2786)

     * Add  a  note  to the user guide recommending the use of a specific Python
       version when creating virtual environments.  Contributed by  @esafak.  (-
       #2808)

     * Fix  aToo  many	open  filesa error due to a file descriptor leak in vir-
       tualenvas locking mechanism. Contributed by @esafak. (#2834)

     * Support	renamed  Windows  venv	redirector  (venvlauncher.exe  and  ven-
       vwlauncher.exe) on Python 3.13 Contributed by @esafak. (#2851)

     * Resolve Nushell activation script deprecation warnings by dynamically se-
       lecting	the  --optional  flag for Nushell get command on version 0.106.0
       and newer, while retaining the deprecated -i flag for older  versions  to
       maintain compatibility. Contributed by @gaborbernat. (#2910)

   v20.32.0 (2025-07-20)
   Features - 20.32.0
     * Warn  on  incorrect invocation of Nushell activation script - by @esafak.
       (#nushell_activation)

     * Discover uv-managed Python installations (#2901)

   Bugfixes - 20.32.0
     * Ignore missing absolute paths for python discovery - by @esafak (#2870)

     * Upgrade embedded setuptools to 80.9.0 from 80.3.1 - by  @gaborbernat.  (-
       #2900)

   v20.31.2 (2025-05-08)
     No significant changes.

   v20.31.1 (2025-05-05)
   Bugfixes - 20.31.1
     * Upgrade embedded wheels:

       * pip to 25.1.1 from 25.1

       * setuptools to 80.3.1 from 78.1.0 (#2880)

   v20.31.0 (2025-05-05)
   Features - 20.31.0
     * No longer bundle wheel wheels (except on Python 3.8), setuptools includes
       native bdist_wheel support.  Update pip to 25.1. (#2868)

   Bugfixes - 20.31.0
     * get_embed_wheel() no longer fails with a TypeError when it is called with
       an unknown distribution.  (#2877)

     * Fix HelpFormatter error with Python 3.14.0b1. (#2878)

   v20.30.0 (2025-03-31)
   Features - 20.30.0
     * Add support for GraalPy. (#2832)

   Bugfixes - 20.30.0
     * Upgrade embedded wheels:

       * setuptools to 78.1.0 from 75.3.2 (#2863)

   v20.29.3 (2025-03-06)
   Bugfixes - 20.29.3
     * Ignore unreadable directories in PATH. (#2794)

   v20.29.2 (2025-02-10)
   Bugfixes - 20.29.2
     * Remove  old  virtualenv	wheel  from  the  source  distribution	-  by  -
       @gaborbernat. (#2841)

     * Upgrade embedded wheel pip to 25.0.1 from 24.3.1 -  by  @gaborbernat.  (-
       #2843)

   v20.29.1 (2025-01-17)
   Bugfixes - 20.29.1
     * Fix PyInfo cache incompatibility warnings - by @robsdedude. (#2827)

   v20.29.0 (2025-01-15)
   Features - 20.29.0
     * Add  support  for  selecting  free-threaded  Python  interpreters,  e.g.,
       python3.13t. (#2809)

   Bugfixes - 20.29.0
     * Upgrade embedded wheels:

       * setuptools to 75.8.0 from 75.6.0 (#2823)

   v20.28.1 (2025-01-02)
   Bugfixes - 20.28.1
     * Skip tcsh tests on broken tcsh versions - by @gaborbernat. (#2814)

   v20.28.0 (2024-11-25)
   Features - 20.28.0
     * Write CACHEDIR.TAG file on creation - by auser:neilramsay. (#2803)

   v20.27.2 (2024-11-25)
   Bugfixes - 20.27.2
     * Upgrade embedded wheels:

       * setuptools to 75.3.0 from 75.2.0 (#2798)

     * Upgrade embedded wheels:

       * wheel to 0.45.0 from 0.44.0

       * setuptools to 75.5.0 (#2800)

     * no longer forcibly echo off during windows batch activation (#2801)

     * Upgrade embedded wheels:

       * setuptools to 75.6.0 from 75.5.0

       * wheel to 0.45.1 from 0.45.0 (#2804)

   v20.27.1 (2024-10-28)
   Bugfixes - 20.27.1
     * Upgrade embedded wheels:

       * pip to 24.3.1 from 24.2 (#2789)

   v20.27.0 (2024-10-17)
   Features - 20.27.0
     * Drop 3.7 support as the CI environments no longer allow it running - by -
       @gaborbernat. (#2758)

   Bugfixes - 20.27.0
     * When a $PATH entry cannot be checked for existence, skip  it  instead  of
       terminating - by @hroncok.  (#2782)

     * Upgrade embedded wheels:

       * setuptools to 75.2.0 from 75.1.0

       * Removed pip of 24.0

       * Removed setuptools of 68.0.0

       * Removed wheel of 0.42.0

       * by @gaborbernat. (#2783)

     * Fix  zipapp is broken on Windows post distlib 0.3.9 - by @gaborbernat. (-
       #2784)

   v20.26.6 (2024-09-27)
   Bugfixes - 20.26.6
     * Properly quote string placeholders in activation script templates to mit-
       igate potential command injection - by @y5c4l3. (#2768)

   v20.26.5 (2024-09-17)
   Bugfixes - 20.26.5
     * Upgrade embedded  wheels:  setuptools  to  75.1.0  from	74.1.2	-  by  -
       @gaborbernat. (#2765)

   v20.26.4 (2024-09-07)
   Bugfixes - 20.26.4
     * no  longer  create () output in console during activation of a virtualenv
       by .bat file. (#2728)

     * Upgrade embedded wheels:

       * wheel to 0.44.0 from 0.43.0

       * pip to 24.2 from 24.1

       * setuptools to 74.1.2 from 70.1.0 (#2760)

   v20.26.3 (2024-06-21)
   Bugfixes - 20.26.3
     * Upgrade embedded wheels:

       * setuptools to 70.1.0 from 69.5.1

       * pip to 24.1 from 24.0 (#2741)

   v20.26.2 (2024-05-13)
   Bugfixes - 20.26.2
     * virtualenv.pyz no longer fails when zipapp path contains a symlink - by -
       @HandSonic and @petamas.  (#1949)

     * Fix bad return  code  from  activate.sh	if  hashing  is  disabled  -  by
       :user:afenkes-ibma. (#2717)

   v20.26.1 (2024-04-29)
   Bugfixes - 20.26.1
     * fix PATH-based Python discovery on Windows - by @ofek. (#2712)

   v20.26.0 (2024-04-23)
   Bugfixes - 20.26.0
     * allow   builtin	 discovery   to  discover  specific  interpreters  (e.g.
       python3.12) given an unspecific spec (e.g.  python3) - by  @flying-sheep.
       (#2709)

   v20.25.3 (2024-04-17)
   Bugfixes - 20.25.3
     * Python 3.13.0a6 renamed pathmod to parser. (#2702)

   v20.25.2 (2024-04-16)
   Bugfixes - 20.25.2
     * Upgrade embedded wheels:

       * setuptools of 69.1.0 to 69.5.1

       * wheel of 0.42.0 to 0.43.0 (#2699)

   v20.25.1 (2024-02-21)
   Bugfixes - 20.25.1
     * Upgrade embedded wheels:

       * setuptools to 69.0.3 from 69.0.2

       * pip to 23.3.2 from 23.3.1 (#2681)

     * Upgrade embedded wheels:

       * pip 23.3.2 to 24.0,

       * setuptools 69.0.3 to 69.1.0. (#2691)

   Misc - 20.25.1
     * #2688

   v20.25.0 (2023-12-01)
   Features - 20.25.0
     * The tests now pass on the CI with Python 3.13.0a2 - by @hroncok. (#2673)

   Bugfixes - 20.25.0
     * Upgrade embedded wheels:

       * wheel to 0.41.3 from 0.41.2 (#2665)

     * Upgrade embedded wheels:

       * wheel to 0.42.0 from 0.41.3

       * setuptools to 69.0.2 from 68.2.2 (#2669)

   v20.24.6 (2023-10-23)
   Bugfixes - 20.24.6
     * Use  get_hookimpls  method  instead of the private attribute in tests. (-
       #2649)

     * Upgrade embedded wheels:

       * setuptools to 68.2.2 from 68.2.0

       * pip to 23.3.1 from 23.2.1 (#2656)

   v20.24.5 (2023-09-08)
   Bugfixes - 20.24.5
     * Declare PyPy 3.10 support - by @cclauss. (#2638)

     * Brew on macOS no longer allows copy builds - disallow choosing this by  -
       @gaborbernat. (#2640)

     * Upgrade embedded wheels:

       * setuptools to 68.2.0 from 68.1.2 (#2642)

   v20.24.4 (2023-08-30)
   Bugfixes - 20.24.4
     * Upgrade embedded wheels:

       * setuptools to 68.1.2 from 68.1.0 on 3.8+

       * wheel to 0.41.2 from 0.41.1 on 3.7+ (#2628)

   v20.24.3 (2023-08-11)
   Bugfixes - 20.24.3
     * Fixed  ResourceWarning  on  exit  caused by periodic update subprocess (-
       #2472)

     * Upgrade embedded wheels:

       * wheel to 0.41.1 from 0.41.0 (#2622)

   Misc - 20.24.3
     * #2610

   v20.24.2 (2023-07-24)
   Bugfixes - 20.24.2
     * Upgrade embedded wheels:

       * pip to 23.2.1 from 23.2

       * wheel to 0.41.0 from 0.40.0 (#2614)

   v20.24.1 (2023-07-19)
   Bugfixes - 20.24.1
     * Upgrade embedded wheels:

       * pip to 23.2 from 23.1.2 - by @arielkirkwood (#2611)

   v20.24.0 (2023-07-14)
   Features - 20.24.0
     * Export the prompt prefix as VIRTUAL_ENV_PROMPT when activating a  virtual
       environment - by @jimporter.  (#2194)

   Bugfixes - 20.24.0
     * Fix test suite - by @gaborbernat. (#2592)

     * Upgrade embedded wheels:

       * setuptools to 68.0.0 from 67.8.0 (#2607)

   v20.23.1 (2023-06-16)
   Bugfixes - 20.23.1
     * update  and simplify nushell activation script, fixes an issue on Windows
       resulting in consecutive command not found - by @melMass. (#2572)

     * Upgrade embedded wheels:

       * setuptools to 67.8.0 from 67.7.2 (#2588)

   v20.23.0 (2023-04-27)
   Features - 20.23.0
     * Do not install wheel and setuptools seed packages for  Python  3.12+.  To
       restore the old behavior use:

       * for   wheel   use   VIRTUALENV_WHEEL=bundle   environment  variable  or
	 --wheel=bundle CLI flag,

       * for setuptools use VIRTUALENV_SETUPTOOLS=bundle environment variable or
	 --setuptools=bundle CLI flag.

       By @chrysle. (#2487)

     * 3.12 support - by @gaborbernat. (#2558)

   Bugfixes - 20.23.0
     * Prevent PermissionError when using venv creator on systems  that  deliver
       files without user write permission - by @kulikjak. (#2543)

     * Upgrade setuptools to 67.7.2 from 67.6.1 and pip to 23.1.2 from 23.1 - by
       @szleb.	(#2560)

   v20.22.0 (2023-04-19)
   Features - 20.22.0
     * Drop  support  for  creating Python <=3.6 (including 2) interpreters. Re-
       moved pip of 20.3.4, 21.3.1;  wheel  of	0.37.1;  setuptools  of  59.6.0,
       44.1.1, 50.3.2- by @gaborbernat. (#2548)

   v20.21.1 (2023-04-19)
   Bugfixes - 20.21.1
     * Add tox.ini to sdist - by @mtelka. (#2511)

     * Move  the use of aleta in nushell to ensure compatibility with future re-
       leases of nushell, where aleta no longer assumes that its initializer  is
       a full expressions. (#2527)

     * The  nushell  command astr collecta has been superseded by the astr joina
       command. The activate.nu script has been updated to reflect this  change.
       (#2532)

     * Upgrade embedded wheels:

       * wheel to 0.40.0 from 0.38.4

       * setuptools to 67.6.1 from 67.4.0

       * pip to 23.1 from 23.0.1 (#2546)

   v20.21.0 (2023-03-12)
   Features - 20.21.0
     * Make closure syntax explicitly starts with {||. (#2512)

   Bugfixes - 20.21.0
     * Add  print  command  to nushell print_prompt to ensure compatibility with
       future release of nushell, where intermediate commands  no  longer  print
       their result to stdout. (#2514)

     * Do not assume the default encoding. (#2515)

     * Make  ReentrantFileLock	thread-safe  and, thereby, fix race condition in
       virtualenv.cli_run - by @radoering. (#2516)

   v20.20.0 (2023-02-28)
   Features - 20.20.0
     * Change environment variable existence check in Nushell activation  script
       to not use deprecated command.  (#2506)

   Bugfixes - 20.20.0
     * Discover  CPython implementations distributed on Windows by any organiza-
       tion - by @faph. (#2504)

     * Upgrade embedded setuptools to 67.4.0 from 67.1.0 and pip to 23.0.1  from
       23.0 - by @gaborbernat. (#2510)

   v20.19.0 (2023-02-07)
   Features - 20.19.0
     * Allow platformdirs version 3 - by @cdce8p. (#2499)

   v20.18.0 (2023-02-06)
   Features - 20.18.0
     * Drop  3.6  runtime  support (can still create 2.7+) - by @gaborbernat. (-
       #2489)

   Bugfixes - 20.18.0
     * Fix broken prompt in Nushell when activating virtual environment -  by  -
       @kubouc. (#2481)

     * Bump  embedded  pip  to 23.0 and setuptools to 67.1 - by @gaborbernat. (-
       #2489)

   v20.17.1 (2022-12-05)
   Bugfixes - 20.17.1
     * A py or python  spec  means  any  Python  rather  than  CPython	-  by  -
       @gaborbernat. (#2460)

     * Make  activate.nu  respect  VIRTUAL_ENV_DISABLE_PROMPT  and  not  set the
       prompt if requested - by @m-lima.  (#2461)

   v20.17.0 (2022-11-27)
   Features - 20.17.0
     * Change Nushell activation script to be a module meant to be activated  as
       an overlay. (#2422)

     * Update  operator  used in Nushell activation script to be compatible with
       future versions. (#2450)

   Bugfixes - 20.17.0
     * Do not use deprecated API from  importlib.resources  on	Python	3.10  or
       later - by @gaborbernat. (#2448)

     * Upgrade	embedded  setuptools to 65.6.3 from 65.5.1 - by @gaborbernat. (-
       #2451)

   v20.16.7 (2022-11-12)
   Bugfixes - 20.16.7
     * Use parent directory of python executable for pyvenv.cfg ahomea value per
       PEP 405 - by @vfazio. (#2440)

     * In  POSIX  virtual  environments,   try	 alternate   binary   names   if
       sys._base_executable does not exist - by @vfazio. (#2442)

     * Upgrade	embedded  wheel to 0.38.4 and pip to 22.3.1 from 22.3 and setup-
       tools to 65.5.1 from 65.5.0 - by @gaborbernat. (#2443)

   v20.16.6 (2022-10-25)
   Features - 20.16.6
     * Drop unneeded shims for PyPy3 directory structure (#2426)

   Bugfixes - 20.16.6
     * Fix  selected  scheme  on  debian  derivatives  for  python   3.10   when
       python3-distutils  is not installed or the venv scheme is not available -
       by @asottile. (#2350)

     * Allow the test suite to pass even with the original C shell (rather  than
       tcsh) - by @kulikjak. (#2418)

     * Fix  fallback  handling of downloading wheels for bundled packages - by -
       @schaap. (#2429)

     * Upgrade embedded setuptools to 65.5.0 from 65.3.0 and pip  to  22.3  from
       22.2.2 - by @gaborbernat. (#2434)

   v20.16.5 (2022-09-07)
   Bugfixes - 20.16.5
     * Do  not	turn echo off for subsequent commands in batch activators (acti-
       vate.bat and deactivate.bat) - by @pawelszramowski. (#2411)

   v20.16.4 (2022-08-29)
   Bugfixes - 20.16.4
     * Bump embed setuptools to 65.3 - by @gaborbernat. (#2405)

   v20.16.3 (2022-08-04)
   Bugfixes - 20.16.3
     * Upgrade embedded pip to 22.2.2 from 22.2.1 and setuptools to 63.4.1  from
       63.2.0 - by @gaborbernat. (#2395)

   v20.16.2 (2022-07-27)
   Bugfixes - 20.16.2
     * Bump embedded pip from 22.2 to 22.2.1 - by @gaborbernat. (#2391)

   v20.16.1 (2022-07-26)
   Features - 20.16.1
     * Update Nushell activation scripts to version 0.67 - by @kubouch. (#2386)

   v20.16.0 (2022-07-25)
   Features - 20.16.0
     * Drop  support for running under Python 2 (still can generate Python 2 en-
       vironments) - by @gaborbernat. (#2382)

     * Upgrade embedded pip to 22.2 from 22.1.2 and setuptools	to  63.2.0  from
       62.6.0 - by @gaborbernat. (#2383)

   v20.15.1 (2022-06-28)
   Bugfixes - 20.15.1
     * Fix the incorrect operation when setuptools plugins output something into
       stdout. (#2335)

     * CPython3Windows creator ignores missing DLLs dir. (#2368)

   v20.15.0 (2022-06-25)
   Features - 20.15.0
     * Support	for  Windows  embeddable  Python  package:  includes python<VER-
       SION>.zip in the creator sources - by @reksarka. (#1774)

   Bugfixes - 20.15.0
     * Upgrade embedded setuptools to 62.3.3 from 62.6.0 and pip to 22.1.2  from
       22.0.4 - by @gaborbernat. (#2348)

     * Use  shlex.quote  instead  of  deprecated  pipes.quote in Python 3 - by -
       @frenzymadness. (#2351)

     * Fix Windows PyPy 3.6 - by @reksarka. (#2363)

   v20.14.1 (2022-04-11)
   Features - 20.14.1
     * Support for creating a virtual environment from a Python 2.7 framework on
       macOS 12 - by @nickhutchinson.  (#2284)

   Bugfixes - 20.14.1
     * Upgrade embedded setuptools to 62.1.0 from 61.0.0 - by  @gaborbernat.  (-
       #2327)

   v20.14.0 (2022-03-25)
   Features - 20.14.0
     * Support Nushell activation scripts with nu version 0.60 - by @kubouch. (-
       #2321)

   Bugfixes - 20.14.0
     * Upgrade	embedded setuptools to 61.0.0 from 60.10.0 - by @gaborbernat. (-
       #2322)

   v20.13.4 (2022-03-18)
   Bugfixes - 20.13.4
     * Improve performance of python startup inside created virtualenvs -  by  -
       @asottile. (#2317)

     * Upgrade	embedded setuptools to 60.10.0 from 60.9.3 - by @gaborbernat. (-
       #2320)

   v20.13.3 (2022-03-07)
   Bugfixes - 20.13.3
     * Avoid symlinking the contents of /usr into PyPy3.8+ virtualenvs	-  by  -
       @stefanor. (#2310)

     * Bump embed pip from 22.0.3 to 22.0.4 - by @gaborbernat. (#2311)

   v20.13.2 (2022-02-24)
   Bugfixes - 20.13.2
     * Upgrade	embedded  setuptools to 60.9.3 from 60.6.0 - by @gaborbernat. (-
       #2306)

   v20.13.1 (2022-02-05)
   Bugfixes - 20.13.1
     * fix aexecv() arg 2 must contain only stringsa error on M1 MacOS (#2282)

     * Upgrade embedded setuptools to 60.5.0 from 60.2.0 - by @asottile. (#2289)

     * Upgrade embedded pip to 22.0.3 and setuptools to 60.6.0 - by @gaborbernat
       and @asottile. (#2294)

   v20.13.0 (2022-01-02)
   Features - 20.13.0
     * Add downloaded wheel information in the relevant JSON embed file to  pre-
       vent additional downloads of the same wheel. - by @mayeut. (#2268)

   Bugfixes - 20.13.0
     * Fix  AttributeError: 'bool' object has no attribute 'error' when creating
       a Python 2.x virtualenv on macOS - by moreati. (#2269)

     * Fix PermissionError: [Errno 1] Operation not permitted  when  creating  a
       Python 2.x virtualenv on macOS/arm64 - by moreati. (#2271)

   v20.12.1 (2022-01-01)
   Bugfixes - 20.12.1
     * Try  using previous updates of pip, setuptools & wheel when inside an up-
       date grace period rather than always falling back to embedded wheels - by
       @mayeut. (#2265)

     * New patch versions of pip, setuptools & wheel are now returned in the ex-
       pected timeframe. - by @mayeut. (#2266)

     * Manual upgrades of pip, setuptools & wheel are not discarded by	a  peri-
       odic update - by @mayeut.  (#2267)

   v20.12.0 (2021-12-31)
   Features - 20.12.0
     * Sign the python2 exe on Darwin arm64 - by @tmspicer. (#2233)

   Bugfixes - 20.12.0
     * Fix --download option - by @mayeut. (#2120)

     * Upgrade	embedded  setuptools to 60.2.0 from 60.1.1 - by @gaborbernat. (-
       #2263)

   v20.11.2 (2021-12-29)
   Bugfixes - 20.11.2
     * Fix installation of pinned versions of pip, setuptools &  wheel	-  by  -
       @mayeut. (#2203)

   v20.11.1 (2021-12-29)
   Bugfixes - 20.11.1
     * Bump embed setuptools to 60.1.1 from 60.1.0 - by @gaborbernat. (#2258)

   v20.11.0 (2021-12-28)
   Features - 20.11.0
     * Avoid deprecation warning from py-filelock argument - by @ofek. (#2237)

     * Upgrade	embedded  setuptools to 61.1.0 from 58.3.0 - by @gaborbernat. (-
       #2240)

     * Drop the runtime dependency of backports.entry-points-selectable -  by  -
       @hroncok. (#2246)

     * Fish: PATH variables should not be quoted when being set - by @d3dave. (-
       #2248)

   v20.10.0 (2021-11-01)
   Features - 20.10.0
     * If a "venv" install scheme exists in sysconfig, virtualenv now uses it to
       create  new  virtual environments.  This allows Python distributors, such
       as Fedora, to patch/replace the default install scheme without  affecting
       the  paths  in new virtual environments. A similar technique was proposed
       to Python, for the venv module - by hroncok (#2208)

     * The activated virtualenv prompt is now  always  wrapped	in  parentheses.
       This  affects venvs created with the --prompt attribute, and matches vir-
       tualenvas behavior on par with venv. (#2224)

   Bugfixes - 20.10.0
     * Fix broken prompt set up by activate.bat - by @SiggyBar. (#2225)

   v20.9.0 (2021-10-23)
   Features - 20.9.0
     * Special-case --prompt . to the name of the current directory -  by  @rkm.
       (#2220)

     * Add libffi-8.dll to pypy windows #2218 - by @mattip

   Bugfixes - 20.9.0
     * Fixed  path  collision that could lead to a PermissionError or writing to
       system directories when using PyPy3.8 - by @mgorny. (#2182)

     * Upgrade embedded setuptools to 58.3.0 from 58.1.0 and pip to 21.3.1  from
       21.2.4 - by @gaborbernat. (#2205)

     * Remove stray closing parenthesis in activate.bat - by @SiggyBar. (#2221)

   v20.8.1 (2021-09-24)
   Bugfixes - 20.8.1
     * Fixed  a bug where while creating a venv on top of an existing one, with-
       out cleaning, when  seeded  wheel  version  mismatch  occurred,	multiple
       .dist-info directories may be present, confounding entrypoint discovery -
       by @arcivanov (#2185)

     * Bump embed setuptools from 58.0.4 to 58.1.0 - by @gaborbernat. (#2195)

   Misc - 20.8.1
     * #2189

   v20.8.0 (2021-09-16)
     * upgrade	embedded setuptools to 58.0.4 from 57.4.0 and pip to 21.2.4 from
       21.2.3

     * Add nushell activation script

   v20.7.2 (2021-08-10)
   Bugfixes - 20.7.2
     * Upgrade embedded pip to 21.2.3 from  21.2.2  and  wheel	to  0.37.0  from
       0.36.2 - by @gaborbernat.  (#2168)

   v20.7.1 (2021-08-09)
   Bugfixes - 20.7.1
     * Fix unpacking dictionary items in PythonInfo.install_path (#2165)

   v20.7.0 (2021-07-31)
   Bugfixes - 20.7.0
     * upgrade	embedded pip to 21.2.2 from 21.1.3 and setuptools to 57.4.0 from
       57.1.0 - by @gaborbernat (#2159)

   Deprecations and Removals - 20.7.0
     * Removed xonsh activator due to this breaking fairly often the CI and lack
       of support from those packages maintainers,  upstream  is  encouraged  to
       continue supporting the project as a plugin - by @gaborbernat. (#2160)

   v20.6.0 (2021-07-14)
   Features - 20.6.0
     * Support	Python	interpreters  without distutils (fallback to syconfig in
       these cases) - by @gaborbernat.	(#1910)

   v20.5.0 (2021-07-13)
   Features - 20.5.0
     * Plugins now use aselectablea entry points - by @jaraco. (#2093)

     * add libffi-7.dll to the hard-coded list of dlls for PyPy (#2141)

     * Use the	better	maintained  platformdirs  instead  of  appdirs	-  by  -
       @gaborbernat. (#2142)

   Bugfixes - 20.5.0
     * Bump  pip  the  embedded  pip  21.1.3  and  setuptools  to  57.1.0 - by -
       @gaborbernat. (#2135)

   Deprecations and Removals - 20.5.0
     * Drop python 3.4 support as it has been over 2 years  since  EOL	-  by  -
       @gaborbernat. (#2141)

   v20.4.7 (2021-05-24)
   Bugfixes - 20.4.7
     * Upgrade	embedded  pip  to  21.1.2  and	setuptools  to	57.0.0	-  by  -
       @gaborbernat. (#2123)

   v20.4.6 (2021-05-05)
   Bugfixes - 20.4.6
     * Fix site.getsitepackages() broken on python2 on debian - by  @freundTech.
       (#2105)

   v20.4.5 (2021-05-05)
   Bugfixes - 20.4.5
     * Bump pip to 21.1.1 from 21.0.1 - by @gaborbernat. (#2104)

     * Fix  site.getsitepackages()  ignoring --system-site-packages on python2 -
       by @freundTech. (#2106)

   v20.4.4 (2021-04-20)
   Bugfixes - 20.4.4
     * Built in  discovery  class  is  always  preferred  over	plugin	supplied
       classes. (#2087)

     * Upgrade embedded setuptools to 56.0.0 by @gaborbernat. (#2094)

   v20.4.3 (2021-03-16)
   Bugfixes - 20.4.3
     * Bump embedded setuptools from 52.0.0 to 54.1.2 - by @gaborbernat (#2069)

     * Fix PyPy3 stdlib on Windows is incorrect - by @gaborbernat. (#2071)

   v20.4.2 (2021-02-01)
   Bugfixes - 20.4.2
     * Running	virtualenv  --upgrade-embed-wheels crashes - by @gaborbernat. (-
       #2058)

   v20.4.1 (2021-01-31)
   Bugfixes - 20.4.1
     * Bump embedded pip and setuptools packages to  latest  upstream  supported
       (21.0.1 and 52.0.0) - by @gaborbernat. (#2060)

   v20.4.0 (2021-01-19)
   Features - 20.4.0
     * On the programmatic API allow passing in the environment variable dictio-
       nary  to  use, defaults to os.environ if not specified - by @gaborbernat.
       (#2054)

   Bugfixes - 20.4.0
     * Upgrade embedded setuptools to 51.3.3 from 51.1.2 - by  @gaborbernat.  (-
       #2055)

   v20.3.1 (2021-01-13)
   Bugfixes - 20.3.1
     * Bump embed pip to 20.3.3, setuptools to 51.1.1 and wheel to 0.36.2 - by -
       @gaborbernat. (#2036)

     * Allow  unfunctioning  of  pydoc to fail freely so that virtualenvs can be
       activated under Zsh with set -e (since otherwise unset -f and  unfunction
       exit with 1 if the function does not exist in Zsh) - by @d125q.	(#2049)

     * Drop  cached  python  information  if  the system executable is no longer
       present (for example when the executable is a shim and  the  mapped  exe-
       cutable	is replaced - such is the case with pyenv) - by @gaborbernat. (-
       #2050)

   v20.3.0 (2021-01-10)
   Features - 20.3.0
     * The builtin discovery takes now a --try-first-with argument and is  first
       attempted as valid interpreters. One can use this to force discovery of a
       given  python executable when the discovery order/mechanism raises errors
       - by @gaborbernat. (#2046)

   Bugfixes - 20.3.0
     * On Windows python 3.7+ distributions where the exe shim is missing  fall-
       back to the old ways - by @gaborbernat. (#1986)

     * When discovering interpreters on Windows, via the PEP-514, prefer Python-
       Core  releases over other ones. virtualenv is used via pip mostly by this
       distribution, so prefer it over other such as conda - by @gaborbernat. (-
       #2046)

   v20.2.2 (2020-12-07)
   Bugfixes - 20.2.2
     * Bump pip to 20.3.1, setuptools to 51.0.0 and  wheel  to	0.36.1	-  by  -
       @gaborbernat. (#2029)

   v20.2.1 (2020-11-23)
     No significant changes.

   v20.2.0 (2020-11-21)
   Features - 20.2.0
     * Optionally skip VCS ignore directive for entire virtualenv directory, us-
       ing option no-vcs-ignore, by default False. (#2003)

     * Add  --read-only-app-data option to allow for creation based on an exist-
       ing app data cache which is non-writable.  This may be useful (for  exam-
       ple) to produce a docker image where the app-data is pre-populated.

	  ENV \
	      VIRTUALENV_OVERRIDE_APP_DATA=/opt/virtualenv/cache \
	      VIRTUALENV_SYMLINK_APP_DATA=1
	  RUN virtualenv venv && rm -rf venv
	  ENV VIRTUALENV_READ_ONLY_APP_DATA=1
	  USER nobody
	  # this virtualenv has symlinks into the read-only app-data cache
	  RUN virtualenv /tmp/venv

       Patch by @asottile. (#2009)

   Bugfixes - 20.2.0
     * Fix  processing of the VIRTUALENV_PYTHON environment variable and make it
       multi-value as well (separated by comma) - by @pneff. (#1998)

   v20.1.0 (2020-10-25)
   Features - 20.1.0
     * The python specification can now take one or more values, first found  is
       used to create the virtual environment - by @gaborbernat. (#1995)

   v20.0.35 (2020-10-15)
   Bugfixes - 20.0.35
     * Bump embedded setuptools from 50.3.0 to 50.3.1 - by @gaborbernat. (#1982)

     * After  importing virtualenv passing cwd to a subprocess calls breaks with
       invalid directory - by @gaborbernat. (#1983)

   v20.0.34 (2020-10-12)
   Bugfixes - 20.0.34
     * Align with venv module when creating virtual  environments  with  builtin
       creator on Windows 3.7 and later - by @gaborbernat. (#1782)

     * Handle	Cygwin	 path  conversion  in  the  activation	script	-  by  -
       @davidcoghlan. (#1969)

   v20.0.33 (2020-10-04)
   Bugfixes - 20.0.33
     * Fix None type error in cygwin if POSIX path in dest  -  by  @danyeaw.  (-
       #1962)

     * Fix  Python  3.4  incompatibilities  (added  back  to  the  CI)	-  by  -
       @gaborbernat. (#1963)

   v20.0.32 (2020-10-01)
   Bugfixes - 20.0.32
     * For activation scripts always use UNIX line endings  (unless  itas  BATCH
       shell related) - by @saytosid. (#1818)

     * Upgrade	embedded  pip  to  20.2.1  and	setuptools  to	49.4.0	-  by  -
       @gaborbernat. (#1918)

     * Avoid spawning new windows when doing seed package upgrades in the  back-
       ground on Windows - by @gaborbernat.  (#1928)

     * Fix  a  bug  that  reading and writing on the same file may cause race on
       multiple processes. (#1938)

     * Upgrade	embedded  setuptools  to  50.2.0  and  pip  to	20.2.3	-  by  -
       @gaborbernat. (#1939)

     * Provide correct path for bash activator in cygwin or msys2 - by @danyeaw.
       (#1940)

     * Relax importlib requirement to allow version<3 - by @usamasadiq (#1953)

     * pth  files  were not processed on CPython2 if $PYTHONPATH was pointing to
       site-packages/ - by @navytux. (#1959) (#1960)

   v20.0.31 (2020-08-17)
   Bugfixes - 20.0.31
     * Upgrade embedded pip to 20.2.1, setuptools to 49.6.0 and wheel to  0.35.1
       - by @gaborbernat. (#1918)

   v20.0.30 (2020-08-04)
   Bugfixes - 20.0.30
     * Upgrade pip to 20.2.1 and setuptools to 49.2.1 - by @gaborbernat. (#1915)

   v20.0.29 (2020-07-31)
   Bugfixes - 20.0.29
     * Upgrade	embedded  pip  from version 20.1.2 to 20.2 - by @gaborbernat. (-
       #1909)

   v20.0.28 (2020-07-24)
   Bugfixes - 20.0.28
     * Fix test suite failing if run from system Python -  by  @gaborbernat.  (-
       #1882)

     * Provide setup_logging flag to python API so that users can bypass logging
       handling if their application already performs this - by @gaborbernat. (-
       #1896)

     * Use  \n	instead if \r\n as line separator for report (because Python al-
       ready performs this transformation automatically upon write to  the  log-
       ging pipe) - by @gaborbernat. (#1905)

   v20.0.27 (2020-07-15)
   Bugfixes - 20.0.27
     * No  longer preimport threading to fix support for gpython and gevent - by
       @navytux. (#1897)

     * Upgrade setuptools from 49.2.0 on Python 3.5+ - by @gaborbernat. (#1898)

   v20.0.26 (2020-07-07)
   Bugfixes - 20.0.26
     * Bump dependency distutils >= 0.3.1 - by @gaborbernat. (#1880)

     * Improve periodic update handling:

       * better logging output while running and enable  logging  on  background
	 process  call ( _VIRTUALENV_PERIODIC_UPDATE_INLINE may be used to debug
	 behavior inline)

       * fallback to unverified context when querying the PyPi for release date,

       * stop downloading wheels once we reach the embedded version,

       by @gaborbernat. (#1883)

     * Do not print error message if the application exists with SystemExit(0) -
       by @gaborbernat. (#1885)

     * Upgrade embedded setuptools from 47.3.1 to 49.1.0 for Python 3.5+ - by  -
       @gaborbernat. (#1887)

   v20.0.25 (2020-06-23)
   Bugfixes - 20.0.25
     * Fix  that when the app-data seeders image creation fails the exception is
       silently ignored. Avoid two virtual environment creations to step on each
       others toes by using  a	lock  while  creating  the  base  images.  By  -
       @gaborbernat. (#1869)

   v20.0.24 (2020-06-22)
   Features - 20.0.24
     * Ensure that the seeded packages do not get too much out of date:

       * add  a  CLI  flag  that  triggers  upgrade  of  embedded  wheels  under
	 upgrade-embed-wheels

       * periodically (once every 14 days) upgrade  the  embedded  wheels  in  a
	 background  process,  and  use them if they have been released for more
	 than 28 days (can be disabled via no-periodic-update)

       More details under Wheel acquisition - by @gaborbernat. (#1821)

     * Upgrade embed wheel content:

       * ship wheels for Python 3.9 and 3.10

       * upgrade setuptools for Python 3.5+ from 47.1.1 to 47.3.1

       by @gaborbernat. (#1841)

     * Display the installed seed package versions in the final summary  output,
       for example:

	  created virtual environment CPython3.8.3.final.0-64 in 350ms
	    creator CPython3Posix(dest=/x, clear=True, global=False)
	    seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/y/virtualenv)
	      added seed packages: pip==20.1.1, setuptools==47.3.1, wheel==0.34.2

       by @gaborbernat. (#1864)

   Bugfixes - 20.0.24
     * Do  not generate/overwrite .gitignore if it already exists at destination
       path - by @gaborbernat. (#1862)

     * Improve error message for no .dist-info inside the app-data copy seeder -
       by @gaborbernat. (#1867)

   Improved Documentation - 20.0.24
     * How seeding mechanisms discover (and automatically keep it  up  to  date)
       wheels at Wheel acquisition - by @gaborbernat. (#1821)

     * How  distributions  should  handle  shipping their own embedded wheels at
       Distribution maintainer patching - by @gaborbernat. (#1840)

   v20.0.23 (2020-06-12)
   Bugfixes - 20.0.23
     * Fix typo in setup.cfg - by @RowdyHowell. (#1857)

   v20.0.22 (2020-06-12)
   Bugfixes - 20.0.22
     * Relax importlib.resources requirement to also allow  version  2	-  by  -
       @asottile. (#1846)

     * Upgrade	embedded  setuptools  to  44.1.1  for  python  2  and 47.1.1 for
       python3.5+ - by @gaborbernat. (#1855)

   v20.0.21 (2020-05-20)
   Features - 20.0.21
     * Generate ignore file for version control systems to avoid  tracking  vir-
       tual  environments  by  default. Users should remove these files if still
       want to track. For now we support only git by @gaborbernat. (#1806)

   Bugfixes - 20.0.21
     * Fix virtualenv fails sometimes when  run  concurrently,	--clear-app-data
       conflicts  with clear flag when abbreviation is turned on. To bypass this
       while allowing abbreviated flags on the command line we had to move it to
       reset-app-data - by @gaborbernat. (#1824)

     * Upgrade embedded setuptools to 46.4.0 from 46.1.3 on Python 3.5+, and pip
       from 20.1 to 20.1.1 - by @gaborbernat. (#1827)

     * Seeder pip now correctly handles --extra-search-dir - by  @frenzymadness.
       (#1834)

   v20.0.20 (2020-05-04)
   Bugfixes - 20.0.20
     * Fix download fails with python 3.4 - by @gaborbernat. (#1809)

     * Fixes  older  CPython2  versions  use  _get_makefile_filename  instead of
       get_makefile_filename on sysconfig - by @ianw. (#1810)

     * Fix download is True by default - by @gaborbernat. (#1813)

     * Fail app-data seed operation when wheel download fails and  better  error
       message - by @gaborbernat. (#1814)

   v20.0.19 (2020-05-03)
   Bugfixes - 20.0.19
     * Fix  generating	a  Python  2  environment  from Python 3 creates invalid
       python activator - by @gaborbernat. (#1776)

     * Fix pinning seed packages via app-data seeder raised Invalid  Requirement
       - by @gaborbernat. (#1779)

     * Do  not	stop  interpreter discovery if we fail to find the system inter-
       preter for a executable during discovery - by @gaborbernat. (#1781)

     * On CPython2 POSIX platforms ensure syconfig.get_makefile_filename  exists
       within  the  virtual  environment (this is used by some c-extension based
       libraries - e.g. numpy - for building) - by @gaborbernat. (#1783)

     * Better handling of options copies and  symlinks.  Introduce  priority  of
       where  the  option  is set to follow the order: CLI, env var, file, hard-
       coded. If both set at same level  prefers  copy	over  symlink.	-  by  -
       @gaborbernat. (#1784)

     * Upgrade	pip  for  Python  2.7  and  3.5+  from	20.0.2	to  20.1  - by -
       @gaborbernat. (#1793)

     * Fix CPython is not discovered from Windows registry, and discover pythons
       from Windows registry in decreasing order by version -  by  @gaborbernat.
       (#1796)

     * Fix symlink detection for creators - by @asottile (#1803)

   v20.0.18 (2020-04-16)
   Bugfixes - 20.0.18
     * Importing  setuptools  before  cli_run could cause our python information
       query to fail due to setuptools patching distutils.dist.Distribution - by
       @gaborbernat. (#1771)

   v20.0.17 (2020-04-09)
   Features - 20.0.17
     * Extend environment variables checked  for  configuration  to  also  check
       aliases	(e.g. setting either VIRTUALENV_COPIES or VIRTUALENV_ALWAYS_COPY
       will work) - by @gaborbernat. (#1763)

   v20.0.16 (2020-04-04)
   Bugfixes - 20.0.16
     * Allow seed wheel files inside the extra-search-dir folders  that  do  not
       have  Requires-Python metadata specified, these are considered compatible
       with all python versions - by @gaborbernat. (#1757)

   v20.0.15 (2020-03-27)
   Features - 20.0.15
     * Upgrade embedded setuptools to 46.1.3 from 46.1.1 - by  @gaborbernat.  (-
       #1752)

   v20.0.14 (2020-03-25)
   Features - 20.0.14
     * Remove  __PYVENV_LAUNCHER__  on macOs for Python 3.7.(<8) and 3.8.(<3) on
       interpreter startup via pth file, this pulls in the upstream patch - by -
       @gaborbernat.  (#1704)

     * Upgrade embedded setuptools for Python 3.5+ to 46.1.1, for Python 2.7  to
       44.1.0 - by @gaborbernat. (#1745)

   Bugfixes - 20.0.14
     * Fix discovery of interpreter by name from PATH that does not match a spec
       format - by @gaborbernat. (#1746)

   v20.0.13 (2020-03-19)
   Bugfixes - 20.0.13
     * Do  not	fail  when the pyc files is missing for the host Python 2 - by -
       @gaborbernat. (#1738)

     * Support broken Packaging pythons that put the include headers under  dis-
       tutils pattern rather than sysconfig one - by @gaborbernat. (#1739)

   v20.0.12 (2020-03-19)
   Bugfixes - 20.0.12
     * Fix relative path discovery of interpreters - by @gaborbernat. (#1734)

   v20.0.11 (2020-03-18)
   Features - 20.0.11
     * Improve	error  message	when the host python does not satisfy invariants
       needed to create virtual environments (now we print which host files  are
       incompatible/missing and for which creators when no supported creator can
       be  matched, however we found creators that can describe the given Python
       interpreter - will still print no supported creator for	Jython,  however
       print  exactly  what host files do not allow creation of virtual environ-
       ments in case of CPython/PyPy) - by @gaborbernat. (#1716)

   Bugfixes - 20.0.11
     * Support Python 3 Framework distributed via XCode in  macOs  Catalina  and
       before - by @gaborbernat. (#1663)

     * Fix  Windows  Store  Python support, do not allow creation via symlink as
       thatas not going to work by design - by @gaborbernat. (#1709)

     * Fix activate_this.py throws AttributeError on Windows when virtual  envi-
       ronment was created via cross python mechanism - by @gaborbernat. (#1710)

     * Fix  --no-pip,  --no-setuptools,  --no-wheel  not  being respected - by -
       @gaborbernat. (#1712)

     * Allow missing .py files if a compiled .pyc version is available	-  by  -
       @tucked. (#1714)

     * Do  not	fail  if the distutils/setuptools patch happens on a C-extension
       loader (such as zipimporter on Python 3.7 or earlier) - by  @gaborbernat.
       (#1715)

     * Support	Python	2  implementations  that  require the landmark files and
       site.py to be in platform standard library instead of  the  standard  li-
       brary  path  of	the virtual environment (notably some RHEL ones, such as
       the Docker image amazonlinux:1) - by @gaborbernat. (#1719)

     * Allow the test suite to pass even when called with the system Python - to
       help repackaging of the tool for Linux distributions -  by  @gaborbernat.
       (#1721)

     * Also  generate pipx.y console script beside pip-x.y to be compatible with
       how pip installs itself - by @gaborbernat. (#1723)

     * Automatically create the application data folder if it does not exists  -
       by @gaborbernat. (#1728)

   Improved Documentation - 20.0.11
     * supports details now explicitly what Python installations we support - by
       @gaborbernat. (#1714)

   v20.0.10 (2020-03-10)
   Bugfixes - 20.0.10
     * Fix acquiring python information might be altered by distutils configura-
       tion  files  generating	incorrect  layout  virtual  environments  - by -
       @gaborbernat. (#1663)

     * Upgrade embedded setuptools to 46.0.0 from 45.3.0 on Python 3.5+ -  by  -
       @gaborbernat. (#1702)

   Improved Documentation - 20.0.10
     * Document  requirements (pip + index server) when installing via pip under
       the installation section - by @gaborbernat. (#1618)

     * Document installing from non PEP-518 systems - @gaborbernat. (#1619)

     * Document installing latest unreleased version from Github - @gaborbernat.
       (#1620)

   v20.0.9 (2020-03-08)
   Bugfixes - 20.0.9
     * pythonw.exe works as python.exe on Windows - by @gaborbernat. (#1686)

     * Handle legacy loaders for virtualenv import hooks used to patch distutils
       configuration load - by @gaborbernat.  (#1690)

     * Support for python 2 platforms that store landmark  files  in  platstdlib
       over stdlib (e.g. RHEL) - by @gaborbernat. (#1694)

     * Upgrade	embedded setuptools to 45.3.0 from 45.2.0 for Python 3.5+ - by -
       @gaborbernat. (#1699)

   v20.0.8 (2020-03-04)
   Bugfixes - 20.0.8
     * Having distutils configuration files that set prefix and  install_scripts
       cause  installation  of packages in the wrong location - by @gaborbernat.
       (#1663)

     * Fix PYTHONPATH being overridden on Python 2 a by @jd. (#1673)

     * Fix list configuration value parsing  from  config  file  or  environment
       variable - by @gaborbernat. (#1674)

     * Fix  Batch  activation script shell prompt to display environment name by
       default - by @spetafree. (#1679)

     * Fix startup on Python 2 is slower for virtualenv - this was due to setup-
       tools calculating itas working set distribution	-  by  @gaborbernat.  (-
       #1682)

     * Fix  entry points are not populated for editable installs on Python 2 due
       to setuptools working set being calculated before easy_install.pth runs -
       by @gaborbernat. (#1684)

     * Fix attr: import fails for setuptools - by @gaborbernat. (#1685)

   v20.0.7 (2020-02-26)
   Bugfixes - 20.0.7
     * Disable distutils fixup for python 3 until pypa/pip #7778  is  fixed  and
       released - by @gaborbernat. (#1669)

   v20.0.6 (2020-02-26)
   Bugfixes - 20.0.6
     * Fix  global  site  package  always  being added with bundled macOs python
       framework builds - by @gaborbernat.  (#1561)

     * Fix generated scripts use host version info rather than	target	-  by  -
       @gaborbernat. (#1600)

     * Fix  circular  prefix  reference with single elements (accept these as if
       they were system executables, print a info about them  referencing  them-
       selves) - by @gaborbernat. (#1632)

     * Handle the case when the application data folder is read-only:

       * the application data folder is now controllable via app-data,

       * clear-app-data  now cleans the entire application data folder, not just
	 the app-data seeder path,

       * check if the application data path passed  in	does  not  exist  or  is
	 read-only, and fallback to a temporary directory,

       * temporary directory application data is automatically cleaned up at the
	 end of execution,

       * symlink-app-data is always False when the application data is temporary

       by @gaborbernat. (#1640)

     * Fix  PyPy  2  builtin  modules are imported from standard library, rather
       than from builtin - by @gaborbernat.  (#1652)

     * Fix creation of entry points when path contains spaces - by @nsoranzo. (-
       #1660)

     * Fix relative paths for the zipapp (for python 3.7+) - by @gaborbernat. (-
       #1666)

   v20.0.5 (2020-02-21)
   Features - 20.0.5
     * Also create pythonX.X executables when creating pypy virtualenvs -  by  -
       @asottile (#1612)

     * Fail  with  better  error message if trying to install source with unsup-
       ported setuptools, allow setuptools-scm >= 2 and move  to  legacy  setup-
       tools-scm  format to support better older platforms (CentOS 7 and such) -
       by @gaborbernat. (#1621)

     * Report of the created virtual environment is now split across four  short
       lines rather than one long - by @gaborbernat (#1641)

   Bugfixes - 20.0.5
     * Add  macOs  Python  2  Framework  support (now we test it with the CI via
       brew) - by @gaborbernat (#1561)

     * Fix losing of libpypy-c.so when the pypy executable is a symlink -  by  -
       @asottile (#1614)

     * Discover  python  interpreter  in  a  case  insensitive	manner	-  by  -
       @PrajwalM2212 (#1624)

     * Fix cross interpreter support when the  host  python  sets  sys.base_exe-
       cutable based on __PYVENV_LAUNCHER__ - by @cjolowicz (#1643)

   v20.0.4 (2020-02-14)
   Features - 20.0.4
     * When aliasing interpreters, use relative symlinks - by @asottile. (#1596)

   Bugfixes - 20.0.4
     * Allow  the  use	of  /  as  pathname  component separator on Windows - by
       vphilippon (#1582)

     * Lower minimal version of six required to 1.9 - by ssbarnea (#1606)

   v20.0.3 (2020-02-12)
   Bugfixes - 20.0.3
     * On Python 2 with Apple Framework builds the global  site  package  is  no
       longer  added  when  the  system-site-packages  is  not	specified - by -
       @gaborbernat. (#1561)

     * Fix system python discovery  mechanism  when  prefixes  contain	relative
       parts  (e.g. ..) by resolving paths within the python information query -
       by @gaborbernat. (#1583)

     * Expose a programmatic API as  from  virtualenv  import  cli_run	-  by  -
       @gaborbernat. (#1585)

     * Fix  app-data  seeder  injects  a  extra  .dist-info.virtualenv path that
       breaks importlib.metadata, now we inject an  extra  .virtualenv	-  by  -
       @gaborbernat. (#1589)

   Improved Documentation - 20.0.3
     * Document  a  programmatic  API  as  from  virtualenv import cli_run under
       Python - by @gaborbernat. (#1585)

   v20.0.2 (2020-02-11)
   Features - 20.0.2
     * Print out a one line message about the created virtual  environment  when
       no  verbose is set, this can now be silenced to get back the original be-
       havior via the quiet flag - by @pradyunsg. (#1557)

     * Allow virtualenvas app data cache to be	overridden  by	VIRTUALENV_OVER-
       RIDE_APP_DATA - by @asottile. (#1559)

     * Passing	in  the virtual environment name/path is now required (no longer
       defaults to venv) - by @gaborbernat. (#1568)

     * Add a CLI flag with-traceback that allows displaying  the  stacktrace  of
       the virtualenv when a failure occurs - by @gaborbernat. (#1572)

   Bugfixes - 20.0.2
     * Support	long  path names for generated virtual environment console entry
       points (such as pip) when using the app-data seeder - by @gaborbernat. (-
       #997)

     * Improve python discovery mechanism:

       * do not fail if there are executables that fail to query (e.g.	for  not
	 having execute access to it) on the PATH,

       * beside  the  prefix  folder also try with the platform dependent binary
	 folder within that,

       by @gaborbernat. (#1545)

     * When copying (either files or trees) do not  copy  the  permission  bits,
       last  access  time,  last modification time, and flags as access to these
       might be forbidden (for example in case of the  macOs  Framework  Python)
       and these are not needed for the user to use the virtual environment - by
       @gaborbernat. (#1561)

     * While  discovering  a  python  executables  interpreters  that  cannot be
       queried are now displayed with info level rather  than  warning,  so  now
       theyare	no  longer  shown  by  default (these can be just executables to
       which we donat have access or that are broken, donat warn if itas not the
       target Python we want) - by @gaborbernat. (#1574)

     * The app-data seeder no longer symlinks the packages on UNIX and copies on
       Windows.  Instead  by  default  always  copies,	however  now   has   the
       symlink-app-data  flag  allowing  users	to  request this less robust but
       faster method - by @gaborbernat. (#1575)

   Improved Documentation - 20.0.2
     * Add link to the legacy documentation for the changelog  by  @jezdez.   (-
       #1547)

     * Fine  tune the documentation layout: default width of theme, allow tables
       to wrap around, soft corners for code snippets - by @pradyunsg. (#1548)

   v20.0.1 (2020-02-10)
   Features - 20.0.1
     * upgrade embedded setuptools to 45.2.0 from 45.1.0 for Python 3.4+ - by  -
       @gaborbernat. (#1554)

   Bugfixes - 20.0.1
     * Virtual	environments  created  via  relative path on Windows creates bad
       console executables - by @gaborbernat.  (#1552)

     * Seems sometimes venvs created set their base executable to themselves; we
       accept these without question, so we handle virtual environments as  sys-
       tem pythons causing issues - by @gaborbernat. (#1553)

   v20.0.0. (2020-02-10)
   Improved Documentation - 20.0.0.
     * Fixes  typos,  repeated	words and inconsistent heading spacing. Rephrase
       parts of the development documentation  and  CLI  documentation.  Expands
       shorthands like env var and config to their full forms. Uses descriptions
       from  respective documentation, for projects listed in related links - by
       @pradyunsg. (#1540)

   v20.0.0b2 (2020-02-04)
   Features - 20.0.0b2
     * Improve base executable discovery mechanism:

       * print at debug level why we refuse some candidates,

       * when no candidates match exactly, instead of hard failing  fallback  to
	 the  closest match where the priority of matching attributes is: python
	 implementation, major version, minor version, architecture, patch  ver-
	 sion,	release  level and serial (this is to facilitate things to still
	 work when the OS upgrade replace/upgrades  the  system  python  with  a
	 never version, than what the virtualenv host python was created with),

       * always  resolve  system_executable  information  during the interpreter
	 discovery, and the discovered environment is the system interpreter in-
	 stead of the venv/virtualenv (this happened  before  lazily  the  first
	 time  we  accessed, and caused reporting that the created virtual envi-
	 ronment is of type of the virtualenv host python  version,  instead  of
	 the  system  pythons  version - these two can differ if the OS upgraded
	 the system python underneath and the virtualenv host  was  created  via
	 copy),

       by @gaborbernat. (#1515)

     * Generate  bash and fish activators on Windows too (as these can be avail-
       able with git bash, cygwin or mysys2) - by @gaborbernat. (#1527)

     * Upgrade	the  bundled  wheel  package  from  0.34.0  to	0.34.2	-  by  -
       @gaborbernat. (#1531)

   Bugfixes - 20.0.0b2
     * Bash  activation  script  should  have no extensions instead of .sh (this
       fixes the virtualenvwrapper integration) - by @gaborbernat. (#1508)

     * Show less information when we run with a single verbosity (-v):

       * no longer shows accepted interpreters information (as the last proposed
	 one is always the accepted one),

       * do not display the str_spec attribute for PythonSpec as  these  can  be
	 deduced from the other attributes,

       * for  the app-data seeder do not show the type of lock, only the path to
	 the app data directory,

       By @gaborbernat. (#1510)

     * Fixed cannot discover a python interpreter that has already been  discov-
       ered  under a different path (such is the case when we have multiple sym-
       links to the same interpreter) - by @gaborbernat. (#1512)

     * Support relative paths for -p - by @gaborbernat. (#1514)

     * Creating virtual environments in parallel fail with cannot  acquire  lock
       within app data - by @gaborbernat.  (#1516)

     * pth  files  were  not processed under Debian CPython2 interpreters - by -
       @gaborbernat. (#1517)

     * Fix prompt not displayed correctly with upcoming fish 3.10 due to us  not
       preserving $pipestatus - by @krobelus. (#1530)

     * Stable  order  within pyenv.cfg and add include-system-site-packages only
       for creators that reference a global Python  -  by  user:gaborbernat.  (-
       #1535)

   Improved Documentation - 20.0.0b2
     * Create the first iteration of the new documentation - by @gaborbernat. (-
       #1465)

     * Project readme is now of type MarkDown instead of reStructuredText - by -
       @gaborbernat. (#1531)

   v20.0.0b1 (2020-01-28)
     * First  public  release  of  the rewrite. Everything is brand new and just
       added.

     * --download defaults to False

     * No longer replaces builtin site module with custom version  baked  within
       virtualenv  code itself. A simple shim module is used to fix up things on
       Python 2 only.

     WARNING:
	The current virtualenv is the second iteration of  implementation.  From
	version  0.8 all the way to 16.7.9 we numbered the first iteration. Ver-
	sion 20.0.0b1 is a complete rewrite of the package, and as such this re-
	lease history starts from there. The old changelog is still available in
	the legacy branch documentation.

AUTHOR
     Author name not set

COPYRIGHT
     2007-2026, PyPA, PyPA

21.2				 August 27, 2026		   VIRTUALENV(1)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=virtualenv&sektion=1&manpath=FreeBSD+Ports+15.1.quarterly>

home | help