virtualenv: Update to upstream v16.7.11.

Based on Miro Hrončok's and Patrick Laimbock's findings:
https://bugzilla.redhat.com/show_bug.cgi?id=1987713

Using upstream commit fb6e546cc1dfd0d363dc4d769486805d2d8f04bc.
This commit is contained in:
Jacek Caban 2021-12-19 23:18:56 +01:00
parent ba7c38da4a
commit 712db1d962
70 changed files with 5371 additions and 2734 deletions

View File

@ -7,6 +7,7 @@ Maintainers
-----------
Brian Rosner
Bernat Gabor
Carl Meyer
Jannis Leidel
Paul Moore
@ -88,4 +89,5 @@ Thomas Aglassinger
Vinay Sajip
Vitaly Babiy
Vladimir Rutsky
Wang Xuerui
Wang Xuerui
Wouter De Borger

View File

@ -0,0 +1,25 @@
virtualenv
==========
See docs/index.rst for user documentation.
Contributor notes
-----------------
* virtualenv is designed to work on python 2 and 3 with a single code base.
Use Python 3 print-function syntax, and always ``use sys.exc_info()[1]``
inside the ``except`` block to get at exception objects.
* Pull requests should be made against ``master`` branch, which is also our
latest stable version.
* All changes to files inside virtualenv_embedded must be integrated to
``virtualenv.py`` with ``tox -e embed``. The tox run will report failure
when changes are integrated, as a flag for CI.
* The codebase must be linted with ``tox -e fix_lint`` before being merged.
The tox run will report failure when the linters revise code, as a flag
for CI.
.. _git-flow: https://github.com/nvie/gitflow
.. _coordinate development: http://nvie.com/posts/a-successful-git-branching-model/

View File

@ -1,12 +1,22 @@
recursive-include docs *
recursive-include tests *.py *.sh *.expected
include virtualenv.py
recursive-include virtualenv_support *.whl
recursive-include virtualenv_embedded *
recursive-exclude docs/_templates *
recursive-exclude docs/_build *
include virtualenv_support/__init__.py
include bin/*
include scripts/*
include *.py
include pyproject.toml
include AUTHORS.txt
include LICENSE.txt
recursive-include tests *
recursive-include docs *
include tasks/*
include tox.ini
exclude readthedocs.yml
exclude CONTRIBUTING.rst
exclude .pre-commit-config.yaml
exclude azure-run-tox-env.yml
exclude azure-pipelines.yml
exclude .gitignore
exclude .gitattributes
recursive-exclude .github *

View File

@ -1,84 +0,0 @@
Metadata-Version: 1.1
Name: virtualenv
Version: 15.2.0
Summary: Virtual Python Environment builder
Home-page: https://virtualenv.pypa.io/
Author: Jannis Leidel, Carl Meyer and Brian Rosner
Author-email: python-virtualenv@groups.google.com
License: MIT
Description: Virtualenv
==========
`Mailing list <http://groups.google.com/group/python-virtualenv>`_ |
`Issues <https://github.com/pypa/virtualenv/issues>`_ |
`Github <https://github.com/pypa/virtualenv>`_ |
`PyPI <https://pypi.python.org/pypi/virtualenv/>`_ |
User IRC: #pypa
Dev IRC: #pypa-dev
Introduction
------------
``virtualenv`` is a tool to create isolated Python environments.
The basic problem being addressed is one of dependencies and versions,
and indirectly permissions. Imagine you have an application that
needs version 1 of LibFoo, but another application requires version
2. How can you use both these applications? If you install
everything into ``/usr/lib/python2.7/site-packages`` (or whatever your
platform's standard location is), it's easy to end up in a situation
where you unintentionally upgrade an application that shouldn't be
upgraded.
Or more generally, what if you want to install an application *and
leave it be*? If an application works, any change in its libraries or
the versions of those libraries can break the application.
Also, what if you can't install packages into the global
``site-packages`` directory? For instance, on a shared host.
In all these cases, ``virtualenv`` can help you. It creates an
environment that has its own installation directories, that doesn't
share libraries with other virtualenv environments (and optionally
doesn't access the globally installed libraries either).
.. comment:
Release History
===============
15.2.0 (2018-03-21)
-------------------
* Upgrade setuptools to 39.0.1.
* Upgrade pip to 9.0.3.
* Upgrade wheel to 0.30.0.
15.1.0 (2016-11-15)
-------------------
* Support Python 3.6.
* Upgrade setuptools to 28.0.0.
* Upgrade pip to 9.0.1.
* Don't install pre-release versions of pip, setuptools, or wheel from PyPI.
`Full Changelog <https://virtualenv.pypa.io/en/latest/changes.html>`_.
Keywords: setuptools deployment installation distutils
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6

View File

@ -4,21 +4,34 @@ virtualenv
A tool for creating isolated 'virtual' python environments.
.. image:: https://img.shields.io/pypi/v/virtualenv.svg
:target: https://pypi.python.org/pypi/virtualenv
.. image:: https://img.shields.io/travis/pypa/virtualenv/develop.svg
:target: http://travis-ci.org/pypa/virtualenv
:target: https://pypi.org/project/virtualenv
:alt: Latest version on PyPi
.. image:: https://img.shields.io/pypi/pyversions/virtualenv.svg
:target: https://pypi.org/project/virtualenv/
:alt: Supported Python versions
.. image:: https://dev.azure.com/pypa/virtualenv/_apis/build/status/pypa.virtualenv?branchName=master
:target: https://dev.azure.com/pypa/virtualenv/_build/latest?definitionId=11&branchName=master
:alt: Azure Pipelines build status
.. image:: https://readthedocs.org/projects/virtualenv/badge/?version=latest&style=flat-square
:target: https://virtualenv.readthedocs.io/en/latest/?badge=latest
:alt: Documentation status
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black
:alt: Code style: black
.. image:: https://pepy.tech/badge/virtualenv/month
:target: https://pepy.tech/project/virtualenv/month
:alt: Downloads
* `Installation <https://virtualenv.pypa.io/en/latest/installation.html>`_
* `Documentation <https://virtualenv.pypa.io/>`_
* `Changelog <https://virtualenv.pypa.io/en/latest/changes.html>`_
* `Issues <https://github.com/pypa/virtualenv/issues>`_
* `PyPI <https://pypi.python.org/pypi/virtualenv/>`_
* `PyPI <https://pypi.org/project/virtualenv/>`_
* `Github <https://github.com/pypa/virtualenv>`_
* `User mailing list <http://groups.google.com/group/python-virtualenv>`_
* `Dev mailing list <http://groups.google.com/group/pypa-dev>`_
* User IRC: #pypa on Freenode.
* Dev IRC: #pypa-dev on Freenode.
* User IRC: `#pypa on Freenode <https://webchat.freenode.net/?channels=%23pypa>`_
* Dev IRC: `#pypa-dev on Freenode <https://webchat.freenode.net/?channels=%23pypa-dev>`_
Code of Conduct

View File

@ -0,0 +1,72 @@
name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr)
resources:
repositories:
- repository: tox
type: github
endpoint: github-gb
name: tox-dev/azure-pipelines-template
ref: master
trigger:
batch: true
branches:
include:
- master
- rewrite
- refs/tags/*
pr:
branches:
include:
- '*'
schedules:
- cron: "12 0 * * *"
displayName: Daily build
branches:
include: [ master, rewrite ]
always: true
variables:
PYTEST_ADDOPTS: "-v -v -ra --showlocals"
PYTEST_XDIST_PROC_NR: 'auto'
CI_RUN: 'yes'
jobs:
- template: run-tox-env.yml@tox
parameters:
jobs:
fix_lint: null
embed: null
cross_python2: null
cross_python3: null
docs: null
py38:
image: [linux, windows, macOs]
py37:
image: [linux, windows, macOs]
py36:
image: [linux, windows, macOs]
py35:
image: [linux, windows, macOs]
py27:
image: [linux, windows, macOs]
dev: null
package_readme: null
before:
- script: 'sudo apt-get update -y && sudo apt-get install fish csh'
condition: and(succeeded(), eq(variables['image_name'], 'linux'), in(variables['TOXENV'], 'py38', 'py37', 'py36', 'py35', 'py34', 'py27'))
displayName: install fish and csh via apt-get
- script: 'brew update -vvv && brew install fish tcsh'
condition: and(succeeded(), eq(variables['image_name'], 'macOs'), in(variables['TOXENV'], 'py38', 'py37', 'py36', 'py35', 'py34', 'py27'))
displayName: install fish and csh via brew
coverage:
with_toxenv: 'coverage' # generate .tox/.coverage, .tox/coverage.xml after test run
for_envs: [py38, py37, py36, py35, py27]
- ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/') }}:
- template: publish-pypi.yml@tox
parameters:
external_feed: 'gb'
pypi_remote: 'pypi-gb'
dependsOn: [fix_lint, embed, cross_python3, cross_python3, docs, report_coverage, dev, package_readme]

View File

@ -1,80 +0,0 @@
#!/usr/bin/env python
"""
Helper script to rebuild virtualenv.py from virtualenv_support
"""
from __future__ import print_function
import os
import re
import codecs
from zlib import crc32 as _crc32
def crc32(data):
"""Python version idempotent"""
return _crc32(data) & 0xffffffff
here = os.path.dirname(__file__)
script = os.path.join(here, '..', 'virtualenv.py')
gzip = codecs.lookup('zlib')
b64 = codecs.lookup('base64')
file_regex = re.compile(
br'##file (.*?)\n([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*convert\("""\n(.*?)"""\)',
re.S)
file_template = b'##file %(filename)s\n%(varname)s = convert("""\n%(data)s""")'
def rebuild(script_path):
with open(script_path, 'rb') as f:
script_content = f.read()
parts = []
last_pos = 0
match = None
for match in file_regex.finditer(script_content):
parts += [script_content[last_pos:match.start()]]
last_pos = match.end()
filename, fn_decoded = match.group(1), match.group(1).decode()
varname = match.group(2)
data = match.group(3)
print('Found file %s' % fn_decoded)
pathname = os.path.join(here, '..', 'virtualenv_embedded', fn_decoded)
with open(pathname, 'rb') as f:
embedded = f.read()
new_crc = crc32(embedded)
new_data = b64.encode(gzip.encode(embedded)[0])[0]
if new_data == data:
print(' File up to date (crc: %08x)' % new_crc)
parts += [match.group(0)]
continue
# Else: content has changed
crc = crc32(gzip.decode(b64.decode(data)[0])[0])
print(' Content changed (crc: %08x -> %08x)' %
(crc, new_crc))
new_match = file_template % {
b'filename': filename,
b'varname': varname,
b'data': new_data
}
parts += [new_match]
parts += [script_content[last_pos:]]
new_content = b''.join(parts)
if new_content != script_content:
print('Content updated; overwriting... ', end='')
with open(script_path, 'wb') as f:
f.write(new_content)
print('done.')
else:
print('No changes in content')
if match is None:
print('No variables were matched/found')
if __name__ == '__main__':
rebuild(script)

View File

@ -1,130 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-compressor.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-compressor.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/django-compressor"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-compressor"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@ -0,0 +1,18 @@
.. examples for changelog entries adding to your Pull Requests
file ``544.doc.rst``::
explain everything much better - by ``passionate_technicalwriter``
file ``544.feature.rst``::
``tox --version`` now shows information about all registered plugins - by ``obestwalter``
file ``571.bugfix.rst``::
``skip_install`` overrides ``usedevelop`` (``usedevelop`` is an option to choose the
installation type if the package is installed and ``skip_install`` determines if it should be
installed at all) - by ``ferdonline``
.. see pyproject.toml for all available categories

View File

@ -0,0 +1,31 @@
{% for section, _ in sections.items() %}
{% set underline = underlines[0] %}
{% if section %}
{{section}}
{{ underline * section|length }}
{% set underline = underlines[1] %}
{% endif %}
{% if sections[section] %}
{% for category, val in definitions.items() if category in sections[section] %}
{{ definitions[category]['name'] }}
{{ underline * definitions[category]['name']|length }}
{% if definitions[category]['showcontent'] %}
{% for text, values in sections[section][category].items() %}
- {{ text }} ({{ values|join(', ') }})
{% endfor %}
{% else %}
- {{ sections[section][category]['']|join(', ') }}
{% endif %}
{% if sections[section][category]|length == 0 %}
No significant changes.
{% endif %}
{% endfor %}
{% else %}
No significant changes.
{% endif %}
{% endfor %}

File diff suppressed because it is too large Load Diff

View File

@ -1,153 +1,73 @@
# -*- coding: utf-8 -*-
#
# Paste documentation build configuration file, created by
# sphinx-quickstart on Tue Apr 22 22:08:49 2008.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# All configuration values have a default value; values that are commented out
# serve to show the default value.
from __future__ import absolute_import, unicode_literals
import os
import re
import subprocess
import sys
from pathlib import Path
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
from virtualenv import __version__
# If your extensions are in another directory, add it here.
sys.path.insert(0, os.path.abspath(os.pardir))
extensions = ["sphinx.ext.autodoc", "sphinx.ext.extlinks"]
source_suffix = ".rst"
master_doc = "index"
project = "virtualenv"
copyright = "2007-2018, Ian Bicking, The Open Planning Project, PyPA"
# General configuration
# ---------------------
ROOT_SRC_TREE_DIR = Path(__file__).parents[1]
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.extlinks']
# Add any paths that contain templates here, relative to this directory.
#templates_path = ['_templates']
def generate_draft_news():
home = "https://github.com"
issue = "{}/issue".format(home)
fragments_path = ROOT_SRC_TREE_DIR / "docs" / "changelog"
for pattern, replacement in (
(r"[^`]@([^,\s]+)", r"`@\1 <{}/\1>`_".format(home)),
(r"[^`]#([\d]+)", r"`#pr\1 <{}/\1>`_".format(issue)),
):
for path in fragments_path.glob("*.rst"):
path.write_text(re.sub(pattern, replacement, path.read_text()))
env = os.environ.copy()
env["PATH"] += os.pathsep.join([os.path.dirname(sys.executable)] + env["PATH"].split(os.pathsep))
changelog = subprocess.check_output(
["towncrier", "--draft", "--version", "DRAFT"], cwd=str(ROOT_SRC_TREE_DIR), env=env
).decode("utf-8")
if "No significant changes" in changelog:
content = ""
else:
note = "*Changes in master, but not released yet are under the draft section*."
content = "{}\n\n{}".format(note, changelog)
(ROOT_SRC_TREE_DIR / "docs" / "_draft.rst").write_text(content)
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
generate_draft_news()
# General substitutions.
project = 'virtualenv'
copyright = '2007-2014, Ian Bicking, The Open Planning Project, PyPA'
version = ".".join(__version__.split(".")[:2])
release = __version__
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
try:
from virtualenv import __version__
# The short X.Y version.
version = '.'.join(__version__.split('.')[:2])
# The full version, including alpha/beta/rc tags.
release = __version__
except ImportError:
version = release = 'dev'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
today_fmt = "%B %d, %Y"
unused_docs = []
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
exclude_patterns = ["changelog/*"]
extlinks = {
'issue': ('https://github.com/pypa/virtualenv/issues/%s', '#'),
'pull': ('https://github.com/pypa/virtualenv/pull/%s', 'PR #'),
"issue": ("https://github.com/pypa/virtualenv/issues/%s", "#"),
"pull": ("https://github.com/pypa/virtualenv/pull/%s", "PR #"),
}
# Options for HTML output
# -----------------------
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
#html_style = 'default.css'
html_theme = 'default'
if not on_rtd:
try:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
pass
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Content template for the index page.
#html_index = ''
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If true, the reST sources are included in the HTML build as _sources/<name>.
#html_copy_source = True
# Output file base name for HTML help builder.
htmlhelp_basename = 'Pastedoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
#latex_documents = []
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
html_theme = "sphinx_rtd_theme"
html_theme_options = {
"canonical_url": "https://virtualenv.pypa.io/en/latest/",
"logo_only": False,
"display_version": True,
"prev_next_buttons_location": "bottom",
"style_external_links": True,
# Toc options
"collapse_navigation": True,
"sticky_navigation": True,
"navigation_depth": 4,
"includehidden": True,
"titles_only": False,
}
html_last_updated_fmt = "%b %d, %Y"
htmlhelp_basename = "Pastedoc"

View File

@ -5,19 +5,24 @@ Contributing
------------
Refer to the `pip development`_ documentation - it applies equally to
virtualenv, except that virtualenv issues should filed on the `virtualenv
virtualenv, except that virtualenv issues should be filed on the `virtualenv
repo`_ at GitHub.
Virtualenv's release schedule is tied to pip's -- each time there's a new pip
release, there will be a new virtualenv release that bundles the new version of
pip.
Files in the `virtualenv_embedded/` subdirectory are embedded into
`virtualenv.py` itself as base64-encoded strings (in order to support
single-file use of `virtualenv.py` without installing it). If your patch
changes any file in `virtualenv_embedded/`, run `bin/rebuild-script.py` to
update the embedded version of that file in `virtualenv.py`; commit that and
submit it as part of your patch / pull request.
Files in the ``virtualenv_embedded/`` subdirectory are embedded into
``virtualenv.py`` itself as base64-encoded strings (in order to support
single-file use of ``virtualenv.py`` without installing it). If your patch
changes any file in ``virtualenv_embedded/``, run ``tox -e embed`` to update
the embedded version of that file in ``virtualenv.py``; commit that and submit
it as part of your patch / pull request. The tox run will report failure
when changes are embedded, as a flag for CI.
The codebase should be linted before a pull request is merged by running
``tox -e fix_lint``. The tox run will report failure when any linting
revisions are required, as a flag for CI.
.. _pip development: https://pip.pypa.io/en/latest/development/
.. _virtualenv repo: https://github.com/pypa/virtualenv/
@ -25,26 +30,16 @@ submit it as part of your patch / pull request.
Running the tests
-----------------
Virtualenv's test suite is small and not yet at all comprehensive, but we aim
to grow it.
The easy way to run tests (handles test dependencies automatically, works with the ``sdist`` too)::
The easy way to run tests (handles test dependencies automatically)::
$ tox
$ python setup.py test
Note you need to first install tox separately by using::
If you want to run only a selection of the tests, you'll need to run them
directly with pytest instead. Create a virtualenv, and install required
packages::
$ python -m pip --user install -U tox
$ pip install pytest mock
Run pytest::
$ pytest
Or select just a single test file to run::
$ pytest tests/test_virtualenv
Run ``python -m tox -av`` for a list of all supported Python environments or just run the
tests in all of the available ones by running just ``tox``.
Status and License
------------------

View File

@ -4,14 +4,23 @@ Virtualenv
`Mailing list <http://groups.google.com/group/python-virtualenv>`_ |
`Issues <https://github.com/pypa/virtualenv/issues>`_ |
`Github <https://github.com/pypa/virtualenv>`_ |
`PyPI <https://pypi.python.org/pypi/virtualenv/>`_ |
`PyPI <https://pypi.org/project/virtualenv/>`_ |
User IRC: #pypa
Dev IRC: #pypa-dev
Introduction
------------
``virtualenv`` is a tool to create isolated Python environments.
``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 <https://docs.python.org/3/library/venv.html>`_.
Note though, that the ``venv`` module does not offer all features of this
library (e.g. cannot create bootstrap scripts, cannot create virtual
environments for other python versions than the host python,
not relocatable, etc.). Tools in general as such still may prefer using
virtualenv for its ease of upgrading (via pip), unified handling of different
Python versions and some more advanced features.
The basic problem being addressed is one of dependencies and versions,
and indirectly permissions. Imagine you have an application that
@ -45,18 +54,6 @@ doesn't access the globally installed libraries either).
development
changes
.. warning::
Python bugfix releases 2.6.8, 2.7.3, 3.1.5 and 3.2.3 include a change that
will cause "import random" to fail with "cannot import name urandom" on any
virtualenv created on a Unix host with an earlier release of Python
2.6/2.7/3.1/3.2, if the underlying system Python is upgraded. This is due to
the fact that a virtualenv uses the system Python's standard library but
contains its own copy of the Python interpreter, so an upgrade to the system
Python results in a mismatch between the version of the Python interpreter
and the version of the standard library. It can be fixed by removing
``$ENV/bin/python`` and re-running virtualenv on the same target directory
with the upgraded Python.
Other Documentation and Links
-----------------------------
@ -76,14 +73,14 @@ Other Documentation and Links
your workflow with many virtualenvs even easier. `His initial blog post on it`__.
He also wrote `an example of using virtualenv to try IPython`__.
.. _virtualenvwrapper: https://pypi.python.org/pypi/virtualenvwrapper/
.. _virtualenvwrapper: https://pypi.org/project/virtualenvwrapper/
.. __: https://doughellmann.com/blog/2008/05/01/virtualenvwrapper/
.. __: https://doughellmann.com/blog/2008/02/01/ipython-and-virtualenv/
* `Pew`_ is another wrapper for virtualenv that makes use of a different
activation technique.
.. _Pew: https://pypi.python.org/pypi/pew/
.. _Pew: https://pypi.org/project/pew/
* `Using virtualenv with mod_wsgi
<http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
@ -103,6 +100,10 @@ Compare & Contrast with Alternatives
There are several alternatives that create isolated environments:
* Python 3's `venv module <https://docs.python.org/3/library/venv.html>`_
is recommended for projects that no longer need to support Python 2 and want
to create just simple environments for the host python.
* ``workingenv`` (which I do not suggest you use anymore) is the
predecessor to this library. It used the main Python interpreter,
but relied on setting ``$PYTHONPATH`` to activate the environment.
@ -125,7 +126,7 @@ There are several alternatives that create isolated environments:
Setuptools automatically, saving a step and avoiding the need for
network access.
* `zc.buildout <http://pypi.python.org/pypi/zc.buildout>`_ doesn't
* `zc.buildout <http://pypi.org/project/zc.buildout>`_ doesn't
create an isolated Python environment in the same style, but
achieves similar results through a declarative config file that sets
up scripts with very particular packages. As a declarative system,

View File

@ -17,36 +17,47 @@ Installation
setuptools < 0.9.7, because easy_install didn't download from PyPI over SSL
and was broken in some subtle ways.
To install globally with `pip` (if you have pip 1.3 or greater installed globally):
In Windows, run the ``pip`` provided by your Python installation to install ``virtualenv``.
::
$ [sudo] pip install virtualenv
> pip install virtualenv
In non-Windows systems it is discouraged to run ``pip`` as root including with ``sudo``.
Generally use your system package manager if it provides a package.
This avoids conflicts in versions and file locations between the system package manager and ``pip``.
See your distribution's package manager documentation for instructions on using it to install ``virtualenv``.
Using ``pip install --user`` is less hazardous but can still cause trouble within the particular user account.
If a system package expects the system provided ``virtualenv`` and an incompatible version is installed with ``--user`` that package may have problems within that user account.
To install within your user account with ``pip`` (if you have pip 1.3 or greater installed):
::
$ pip install --user virtualenv
Note: The specific ``bin`` path may vary per distribution but is often ``~/.local/bin`` and must be added to your ``$PATH`` if not already present.
Or to get the latest unreleased dev version:
::
$ [sudo] pip install https://github.com/pypa/virtualenv/tarball/master
$ pip install --user https://github.com/pypa/virtualenv/tarball/master
To install version X.X globally from source:
To install version ``X.X.X`` globally from source:
::
$ curl -O https://pypi.python.org/packages/source/v/virtualenv/virtualenv-X.X.tar.gz
$ tar xvfz virtualenv-X.X.tar.gz
$ cd virtualenv-X.X
$ [sudo] python setup.py install
$ pip install --user https://github.com/pypa/virtualenv/tarball/X.X.X
To *use* locally from source:
::
$ curl -O https://pypi.python.org/packages/source/v/virtualenv/virtualenv-X.X.tar.gz
$ tar xvfz virtualenv-X.X.tar.gz
$ cd virtualenv-X.X
$ curl --location --output virtualenv-X.X.X.tar.gz https://github.com/pypa/virtualenv/tarball/X.X.X
$ tar xvfz virtualenv-X.X.X.tar.gz
$ cd pypa-virtualenv-YYYYYY
$ python virtualenv.py myVE
.. note::

View File

@ -1,170 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-compressor.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-compressor.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@ -40,7 +40,7 @@ Options
.. option:: -p PYTHON_EXE, --python=PYTHON_EXE
The Python interpreter to use, e.g.,
--python=python2.5 will use the python2.5 interpreter
``--python=python2.5`` will use the python2.5 interpreter
to create the new environment. The default is the
interpreter that virtualenv was installed with
(like ``/usr/bin/python``)
@ -111,8 +111,8 @@ Options
virtualenv. Distribute has now been merged into Setuptools, and the
latter is always installed.
.. _Distribute: https://pypi.python.org/pypi/distribute
.. _Setuptools: https://pypi.python.org/pypi/setuptools
.. _Distribute: https://pypi.org/project/distribute
.. _Setuptools: https://pypi.org/project/setuptools
Configuration
@ -148,8 +148,10 @@ is the same as calling::
.. envvar:: VIRTUAL_ENV_DISABLE_PROMPT
Any virtualenv created when this is set to a non-empty value will not have
it's :ref:`activate` modify the shell prompt.
Any virtualenv *activated* when this is set to a non-empty value will leave
the shell prompt unchanged during processing of the
:ref:`activate script <activate>`, rather than modifying it to indicate
the newly activated environment.
Configuration File
@ -189,6 +191,15 @@ environment. Developers may find it useful to distribute a script
that sets up a particular environment, for example a script that
installs a particular web application.
.. note::
A bootstrap script requires a ``virtualenv_support`` directory containing
``pip`` and ``setuptools`` wheels alongside it, just like the actual virtualenv
script. Running a bootstrap script without a ``virtualenv_support`` directory
is unsupported (but if you use ``--no-setuptools`` and manually install ``pip``
and ``setuptools`` in your virtualenv, it will work).
To create a script like this, call
:py:func:`virtualenv.create_bootstrap_script`, and write the
result to your new bootstrapping script.
@ -259,3 +270,62 @@ Here's a more concrete example of how you could use this::
Another example is available `here`__.
.. __: https://github.com/socialplanning/fassembler/blob/master/fassembler/create-venv-script.py
Compatibility with the stdlib venv module
-----------------------------------------
Starting with Python 3.3, the Python standard library includes a ``venv``
module that provides similar functionality to ``virtualenv`` - however, the
mechanisms used by the two modules are very different.
Problems arise when environments get "nested" (a virtual environment is
created from within another one - for example, running the virtualenv tests
using tox, where tox creates a virtual environment to run the tests, and the
tests themselves create further virtual environments).
``virtualenv`` supports creating virtual environments from within another one
(the ``sys.real_prefix`` variable allows ``virtualenv`` to locate the "base"
environment) but stdlib-style ``venv`` environments don't use that mechanism,
so explicit support is needed for those environments.
A standard library virtual environment is most easily identified by checking
``sys.prefix`` and ``sys.base_prefix``. If these differ, the interpreter is
running in a virtual environment and the base interpreter is located in the
directory specified by ``sys.base_prefix``. Therefore, when
``sys.base_prefix`` is set, virtualenv gets the interpreter files from there
rather than from ``sys.prefix`` (in the same way as ``sys.real_prefix`` is
used for virtualenv-style environments). In practice, this is sufficient for
all platforms other than Windows.
On Windows from Python 3.7.2 onwards, a stdlib-style virtual environment does
not contain an actual Python interpreter executable, but rather a "redirector"
which launches the actual interpreter from the base environment (this
redirector is based on the same code as the standard ``py.exe`` launcher). As
a result, the virtualenv approach of copying the interpreter from the starting
environment fails. In order to correctly set up the virtualenv, therefore, we
need to be running from a "full" environment. To ensure that, we re-invoke the
``virtualenv.py`` script using the "base" interpreter, in the same way as we
do with the ``--python`` command line option.
The process of identifying the base interpreter is complicated by the fact
that the implementation changed between different Python versions. The
logic used is as follows:
1. If the (private) attribute ``sys._base_executable`` is present, this is
the base interpreter. This is the long-term solution and should be stable
in the future (the attribute may become public, and have the leading
underscore removed, in a Python 3.8, but that is not confirmed yet).
2. In the absence of ``sys._base_executable`` (only the case for Python 3.7.2)
we check for the existence of the environment variable
``__PYVENV_LAUNCHER__``. This is used by the redirector, and if it is
present, we know that we are in a stdlib-style virtual environment and need
to locate the base Python. In most cases, the base environment is located
at ``sys.base_prefix`` - however, in the case where the user creates a
virtualenv, and then creates a venv from that virtualenv,
``sys.base_prefix`` is not correct - in that case, though, we have
``sys.real_prefix`` (set by virtualenv) which *is* correct.
There is one further complication - as noted above, the environment variable
``__PYVENV_LAUNCHER__`` affects how the interpreter works, so before we
re-invoke the virtualenv script, we remove this from the environment.

View File

@ -9,7 +9,7 @@ Virtualenv has one basic command::
$ virtualenv ENV
Where ``ENV`` is a directory to place the new virtual environment. It has
Where ``ENV`` is a directory in which to place the new virtual environment. It has
a number of usual effects (modifiable by many :ref:`options`):
- :file:`ENV/lib/` and :file:`ENV/include/` are created, containing supporting
@ -27,8 +27,8 @@ a number of usual effects (modifiable by many :ref:`options`):
The python in your new virtualenv is effectively isolated from the python that
was used to create it.
.. _pip: https://pypi.python.org/pypi/pip
.. _setuptools: https://pypi.python.org/pypi/setuptools
.. _pip: https://pypi.org/project/pip
.. _setuptools: https://pypi.org/project/setuptools
.. _activate:
@ -40,9 +40,9 @@ In a newly created virtualenv there will also be a :command:`activate` shell
script. For Windows systems, activation scripts are provided for
the Command Prompt and Powershell.
On Posix systems, this resides in :file:`/ENV/bin/`, so you can run::
On Posix systems, this resides in :file:`ENV/bin/`, so you can run::
$ source bin/activate
$ source /path/to/ENV/bin/activate
For some shells (e.g. the original Bourne Shell) you may need to use the
:command:`.` command, when :command:`source` does not exist. There are also
@ -52,10 +52,20 @@ separate activate files for some other shells, like csh and fish.
This will change your ``$PATH`` so its first entry is the virtualenv's
``bin/`` directory. (You have to use ``source`` because it changes your
shell environment in-place.) This is all it does; it's purely a
convenience. If you directly run a script or the python interpreter
convenience.
If you directly run a script or the python interpreter
from the virtualenv's ``bin/`` directory (e.g. ``path/to/ENV/bin/pip``
or ``/path/to/ENV/bin/python-script.py``) there's no need for
activation.
or ``/path/to/ENV/bin/python-script.py``) then ``sys.path`` will
automatically be set to use the Python libraries associated with the
virtualenv. But, unlike the activation scripts, the environment variables
``PATH`` and ``VIRTUAL_ENV`` will *not* be modified. This means that if
your Python script uses e.g. ``subprocess`` to run another Python script
(e.g. via a ``#!/usr/bin/env python`` shebang line) the second script
*may not be executed with the same Python binary as the first* nor have
the same libraries available to it. To avoid this happening your first
script will need to modify the environment variables in the same manner
as the activation scripts, before the second script is executed.
The ``activate`` script will also modify your shell prompt to indicate
which environment is currently active. To disable this behaviour, see
@ -65,7 +75,7 @@ To undo these changes to your path (and prompt), just run::
$ deactivate
On Windows, the equivalent `activate` script is in the ``Scripts`` folder::
On Windows, the equivalent ``activate`` script is in the ``Scripts`` folder::
> \path\to\env\Scripts\activate
@ -80,7 +90,7 @@ below.
If using Powershell, the ``activate`` script is subject to the
`execution policies`_ on the system. By default on Windows 7, the system's
excution policy is set to ``Restricted``, meaning no scripts like the
execution policy is set to ``Restricted``, meaning no scripts like the
``activate`` script are allowed to be executed. But that can't stop us
from changing that slightly to allow it to be executed.
@ -125,6 +135,15 @@ below.
Since the ``activate.ps1`` script is generated locally for each virtualenv,
it is not considered a remote script and can then be executed.
On xonsh, the equivalent ``activate`` script is called ``activate.xsh``, and
lives in either the ``bin/`` directory (on posix systems) or the ``Scripts\``
directory (on Windows). For example::
$ source /path/to/ENV/bin/activate.xsh
With xonsh, you may still run the ``deactivate`` command to undo the changes.
.. _`execution policies`: http://technet.microsoft.com/en-us/library/dd347641.aspx
Removing an Environment
@ -147,6 +166,10 @@ This can be used if you have control over the global site-packages directory,
and you want to depend on the packages there. If you want isolation from the
global system, do not use this flag.
If you need to change this option after creating a virtual environment, you can
add (to turn off) or remove (to turn on) the file ``no-global-site-packages.txt``
from ``lib/python3.7/`` or equivalent in the environments directory.
Windows Notes
~~~~~~~~~~~~~
@ -155,7 +178,7 @@ executables on Windows go in ``ENV\Scripts\`` instead of ``ENV/bin/`` and
libraries go in ``ENV\Lib\`` rather than ``ENV/lib/``.
To create a virtualenv under a path with spaces in it on Windows, you'll need
the `win32api <http://sourceforge.net/projects/pywin32/>`_ library installed.
the `win32api <https://github.com/mhammond/pywin32/>`_ library installed.
Using Virtualenv without ``bin/python``
@ -172,7 +195,7 @@ the path is correct. A script is available to correct the path. You
can setup the environment like::
activate_this = '/path/to/env/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))
exec(open(activate_this).read(), {'__file__': activate_this})
This will change ``sys.path`` and even change ``sys.prefix``, but also allow
you to use an existing interpreter. Items in your environment will show up
@ -255,4 +278,3 @@ As well as the extra directories, the search order includes:
#. The ``virtualenv_support`` directory relative to virtualenv.py
#. The directory where virtualenv.py is located.
#. The current directory.

View File

@ -0,0 +1,51 @@
[build-system]
requires = [
"setuptools >= 40.6.3",
"wheel >= 0.29.0",
]
build-backend = 'setuptools.build_meta'
[tool.black]
line-length = 120
[tool.towncrier]
package = "virtualenv"
filename = "docs/changes.rst"
directory = "docs/changelog"
template = "docs/changelog/template.jinja2"
title_format = "v{version} ({project_date})"
issue_format = "`#{issue} <https://github.com/pypa/virtualenv/issues/{issue}>`_"
underlines = ["-", "^"]
[[tool.towncrier.section]]
path = ""
[[tool.towncrier.type]]
directory = "bugfix"
name = "Bugfixes"
showcontent = true
[[tool.towncrier.type]]
directory = "feature"
name = "Features"
showcontent = true
[[tool.towncrier.type]]
directory = "deprecation"
name = "Deprecations (removal in next major release)"
showcontent = true
[[tool.towncrier.type]]
directory = "breaking"
name = "Backward incompatible changes"
showcontent = true
[[tool.towncrier.type]]
directory = "doc"
name = "Documentation"
showcontent = true
[[tool.towncrier.type]]
directory = "misc"
name = "Miscellaneous"
showcontent = true

View File

@ -0,0 +1,8 @@
build:
image: latest
python:
version: 3.6
pip_install: true
extra_requirements:
- docs
formats: []

View File

@ -1,3 +0,0 @@
#!/usr/bin/env python
import virtualenv
virtualenv.main()

View File

@ -1,7 +1,81 @@
[metadata]
name = virtualenv
description = Virtual Python Environment builder
long_description = file: README.rst
keywords = virtual, environments, isolated
maintainer = Bernat Gabor
author = Ian Bicking
maintainer-email = gaborjbernat@gmail.com
author-email = ianb@colorstudy.com
url = https://virtualenv.pypa.io/
project_urls =
Source=https://github.com/pypa/virtualenv
Tracker=https://github.com/pypa/virtualenv/issues
classifiers = Development Status :: 5 - Production/Stable
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: POSIX
Operating System :: Microsoft :: Windows
Operating System :: MacOS :: MacOS X
Topic :: Software Development :: Testing
Topic :: Software Development :: Libraries
Topic :: Utilities
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
platforms = any
license = MIT
license_file = LICENSE.txt
[options]
packages = find:
include_package_data = True
zip_safe = True
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
[options.extras_require]
testing = mock;python_version<"3.3"
pytest >= 4.0.0, <5
coverage >= 4.5.0, <5
pytest-timeout >= 1.3.0, <2
xonsh; python_version>="3.5"
six >= 1.10.0, < 2
pytest-xdist
pytest-localserver
pypiserver
docs = sphinx >= 1.8.0, < 2
towncrier >= 18.5.0
sphinx_rtd_theme >= 0.4.2, < 1
[options.packages.find]
where = .
[options.package_data]
virtualenv_support = *.whl
[options.entry_points]
console_scripts = virtualenv=virtualenv:main
[sdist]
formats = gztar
[bdist_wheel]
universal = 1
universal = true
[egg_info]
tag_build =
tag_date = 0
[coverage:run]
branch = false
parallel = true
[coverage:report]
skip_covered = True
show_missing = True
[coverage:paths]
source = .
.tox/*/*/site-packages
.tox/*/*/*/site-packages
*/s

View File

@ -1,123 +1,16 @@
import os
import re
import shutil
import sys
if sys.version_info[:2] < (2, 6):
sys.exit('virtualenv requires Python 2.6 or higher.')
try:
from setuptools import setup
from setuptools.command.test import test as TestCommand
class PyTest(TestCommand):
user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = []
def finalize_options(self):
TestCommand.finalize_options(self)
#self.test_args = []
#self.test_suite = True
def run_tests(self):
# import here, because outside the eggs aren't loaded
import pytest
sys.exit(pytest.main(self.pytest_args))
setup_params = {
'entry_points': {
'console_scripts': ['virtualenv=virtualenv:main'],
},
'zip_safe': False,
'cmdclass': {'test': PyTest},
'tests_require': ['pytest', 'mock'],
}
except ImportError:
from distutils.core import setup
if sys.platform == 'win32':
print('Note: without Setuptools installed you will '
'have to use "python -m virtualenv ENV"')
setup_params = {}
else:
script = 'scripts/virtualenv'
setup_params = {'scripts': [script]}
def read_file(*paths):
here = os.path.dirname(os.path.abspath(__file__))
with open(os.path.join(here, *paths)) as f:
return f.read()
# Get long_description from index.rst:
long_description = read_file('docs', 'index.rst')
long_description = long_description.strip().split('split here', 1)[0]
# Add release history
changes = read_file('docs', 'changes.rst')
# Only report last two releases for brevity
releases_found = 0
change_lines = []
for line in changes.splitlines():
change_lines.append(line)
if line.startswith('--------------'):
releases_found += 1
if releases_found > 2:
break
changes = '\n'.join(change_lines[:-2]) + '\n'
changes += '`Full Changelog <https://virtualenv.pypa.io/en/latest/changes.html>`_.'
# Replace issue/pull directives
changes = re.sub(r':pull:`(\d+)`', r'PR #\1', changes)
changes = re.sub(r':issue:`(\d+)`', r'#\1', changes)
long_description += '\n\n' + changes
from setuptools import setup
def get_version():
version_file = read_file('virtualenv.py')
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
version_file, re.M)
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "virtualenv.py")) as file_handler:
version_file = file_handler.read()
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M)
if version_match:
return version_match.group(1)
raise RuntimeError("Unable to find version string.")
# Hack to prevent stupid TypeError: 'NoneType' object is not callable error on
# exit of python setup.py test # in multiprocessing/util.py _exit_function when
# running python setup.py test (see
# http://www.eby-sarna.com/pipermail/peak/2010-May/003357.html)
try:
import multiprocessing # noqa
except ImportError:
pass
setup(
name='virtualenv',
version=get_version(),
description="Virtual Python Environment builder",
long_description=long_description,
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
keywords='setuptools deployment installation distutils',
author='Ian Bicking',
author_email='ianb@colorstudy.com',
maintainer='Jannis Leidel, Carl Meyer and Brian Rosner',
maintainer_email='python-virtualenv@groups.google.com',
url='https://virtualenv.pypa.io/',
license='MIT',
py_modules=['virtualenv'],
packages=['virtualenv_support'],
package_data={'virtualenv_support': ['*.whl']},
**setup_params)
setup(version=get_version(), py_modules=["virtualenv"], setup_requires=["setuptools >= 40.6.3"])

View File

@ -0,0 +1,37 @@
"""https://docs.python.org/3/library/zipapp.html"""
import argparse
import io
import os.path
import zipapp
import zipfile
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--root", default=".")
parser.add_argument("--dest")
args = parser.parse_args()
if args.dest is not None:
dest = args.dest
else:
dest = os.path.join(args.root, "virtualenv.pyz")
bio = io.BytesIO()
with zipfile.ZipFile(bio, "w") as zipf:
filenames = ["LICENSE.txt", "virtualenv.py"]
for whl in os.listdir(os.path.join(args.root, "virtualenv_support")):
filenames.append(os.path.join("virtualenv_support", whl))
for filename in filenames:
zipf.write(os.path.join(args.root, filename), filename)
zipf.writestr("__main__.py", "import virtualenv; virtualenv.main()")
bio.seek(0)
zipapp.create_archive(bio, dest)
print("zipapp created at {}".format(dest))
if __name__ == "__main__":
exit(main())

View File

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
"""Handles creating a release PR"""
from pathlib import Path
from subprocess import check_call
from typing import Tuple
from git import Commit, Head, Remote, Repo, TagReference
from packaging.version import Version
ROOT_SRC_DIR = Path(__file__).resolve().parents[1]
def main(version_str: str) -> None:
version = Version(version_str)
repo = Repo(str(ROOT_SRC_DIR))
if repo.is_dirty():
raise RuntimeError("Current repository is dirty. Please commit any changes and try again.")
upstream, release_branch = create_release_branch(repo, version)
release_commit = release_changelog(repo, version)
tag = tag_release_commit(release_commit, repo, version)
print("push release commit")
repo.git.push(upstream.name, release_branch)
print("push release tag")
repo.git.push(upstream.name, tag)
print("All done! ✨ 🍰 ✨")
def create_release_branch(repo: Repo, version: Version) -> Tuple[Remote, Head]:
print("create release branch from upstream legacy")
upstream = get_upstream(repo)
upstream.fetch()
branch_name = f"release-{version}"
release_branch = repo.create_head(branch_name, upstream.refs.legacy, force=True)
upstream.push(refspec=f"{branch_name}:{branch_name}", force=True)
release_branch.set_tracking_branch(repo.refs[f"{upstream.name}/{branch_name}"])
release_branch.checkout()
return upstream, release_branch
def get_upstream(repo: Repo) -> Remote:
upstream_remote = "pypa/virtualenv.git"
urls = set()
for remote in repo.remotes:
for url in remote.urls:
if url.endswith(upstream_remote):
return remote
urls.add(url)
raise RuntimeError(f"could not find {upstream_remote} remote, has {urls}")
def release_changelog(repo: Repo, version: Version) -> Commit:
print("generate release commit")
check_call(["towncrier", "--yes", "--version", version.public], cwd=str(ROOT_SRC_DIR))
release_commit = repo.index.commit(f"release {version}")
return release_commit
def tag_release_commit(release_commit, repo, version) -> TagReference:
print("tag release commit")
existing_tags = [x.name for x in repo.tags]
if version in existing_tags:
print("delete existing tag {}".format(version))
repo.delete_tag(version)
print("create tag {}".format(version))
tag = repo.create_tag(version, ref=release_commit, force=True)
return tag
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(prog="release")
parser.add_argument("--version", required=True)
options = parser.parse_args()
main(options.version)

View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
"""
Helper script to rebuild virtualenv.py from virtualenv_support
"""
from __future__ import print_function, unicode_literals
import codecs
import os
import re
import sys
from zlib import crc32 as _crc32
if sys.version_info < (3,):
print("requires Python 3 (use tox from Python 3 if invoked via tox)")
raise SystemExit(1)
def crc32(data):
"""Python version idempotent"""
return _crc32(data.encode()) & 0xFFFFFFFF
here = os.path.realpath(os.path.dirname(__file__))
script = os.path.realpath(os.path.join(here, "..", "virtualenv.py"))
gzip = codecs.lookup("zlib")
b64 = codecs.lookup("base64")
file_regex = re.compile(r'# file (.*?)\n([a-zA-Z][a-zA-Z0-9_]+) = convert\(\n """\n(.*?)"""\n\)', re.S)
file_template = '# file {filename}\n{variable} = convert(\n """\n{data}"""\n)'
def rebuild(script_path):
with open(script_path, "rt") as current_fh:
script_content = current_fh.read()
script_parts = []
match_end = 0
next_match = None
_count, did_update = 0, False
for _count, next_match in enumerate(file_regex.finditer(script_content)):
script_parts += [script_content[match_end : next_match.start()]]
match_end = next_match.end()
filename, variable_name, previous_encoded = next_match.group(1), next_match.group(2), next_match.group(3)
differ, content = handle_file(next_match.group(0), filename, variable_name, previous_encoded)
script_parts.append(content)
if differ:
did_update = True
script_parts += [script_content[match_end:]]
new_content = "".join(script_parts)
report(1 if not _count or did_update else 0, new_content, next_match, script_content, script_path)
def handle_file(previous_content, filename, variable_name, previous_encoded):
print("Found file {}".format(filename))
current_path = os.path.realpath(os.path.join(here, "..", "virtualenv_embedded", filename))
_, file_type = os.path.splitext(current_path)
keep_line_ending = file_type in (".bat",)
with open(current_path, "rt", encoding="utf-8", newline="" if keep_line_ending else None) as current_fh:
current_text = current_fh.read()
current_crc = crc32(current_text)
current_encoded = b64.encode(gzip.encode(current_text.encode())[0])[0].decode()
if current_encoded == previous_encoded:
print(" File up to date (crc: {:08x})".format(current_crc))
return False, previous_content
# Else: content has changed
previous_text = gzip.decode(b64.decode(previous_encoded.encode())[0])[0].decode()
previous_crc = crc32(previous_text)
print(" Content changed (crc: {:08x} -> {:08x})".format(previous_crc, current_crc))
new_part = file_template.format(filename=filename, variable=variable_name, data=current_encoded)
return True, new_part
def report(exit_code, new, next_match, current, script_path):
if new != current:
print("Content updated; overwriting... ", end="")
with open(script_path, "wt") as current_fh:
current_fh.write(new)
print("done.")
else:
print("No changes in content")
if next_match is None:
print("No variables were matched/found")
raise SystemExit(exit_code)
if __name__ == "__main__":
rebuild(script)

View File

@ -0,0 +1,48 @@
"""
Helper script to rebuild virtualenv_support. Downloads the wheel files using pip
"""
from __future__ import absolute_import, unicode_literals
import glob
import os
import subprocess
def virtualenv_support_path():
return os.path.join(os.path.dirname(__file__), "..", "virtualenv_support")
def collect_wheels():
for filename in glob.glob(os.path.join(virtualenv_support_path(), "*.whl")):
name, version = os.path.basename(filename).split("-")[:2]
yield filename, name, version
def remove_wheel_files():
old_versions = {}
for filename, name, version in collect_wheels():
old_versions[name] = version
os.remove(filename)
return old_versions
def download(package):
subprocess.call(["pip", "download", "-d", virtualenv_support_path(), package])
def run():
old = remove_wheel_files()
for package in ("pip", "wheel", "setuptools"):
download(package)
new = {name: version for _, name, version in collect_wheels()}
changes = []
for package, version in old.items():
if new[package] != version:
changes.append((package, version, new[package]))
print("\n".join(" * upgrade {} from {} to {}".format(p, o, n) for p, o, n in changes))
if __name__ == "__main__":
run()

View File

@ -0,0 +1,104 @@
"""Activate this does not mangles with the shell itself to provision the python, but instead mangles
with the caller interpreter, effectively making so that the virtualenv activation constraints are met once
it's loaded.
While initially may feel like a import is all we need, import is executed only once not at every activation. To
work around this we'll use Python 2 execfile, and Python 3 exec(read()).
Virtual env activation constraints that we guarantee:
- the virtualenv site-package will be visible from the activator Python
- virtualenv packages take priority over python 2
- virtualenv bin PATH pre-pended
- VIRTUAL_ENV env var will be set.
- if the user tries to import we'll raise
"""
from __future__ import absolute_import, unicode_literals
import os
import re
import subprocess
import sys
import textwrap
def test_activate_this(clean_python, tmp_path, monkeypatch):
# to test this, we'll try to use the activation env from this Python
monkeypatch.delenv(str("VIRTUAL_ENV"), raising=False)
monkeypatch.delenv(str("PYTHONPATH"), raising=False)
paths = [str(tmp_path), str(tmp_path / "other")]
start_path = os.pathsep.join(paths)
monkeypatch.setenv(str("PATH"), start_path)
activator = tmp_path.__class__(clean_python[1]) / "activate_this.py"
assert activator.exists()
activator_at = str(activator)
script = textwrap.dedent(
"""
import os
import sys
print(os.environ.get("VIRTUAL_ENV"))
print(os.environ.get("PATH"))
try:
import pydoc_test
raise RuntimeError("this should not happen")
except ImportError:
pass
print(os.pathsep.join(sys.path))
file_at = {!r}
exec(open(file_at).read(), {{'__file__': file_at}})
print(os.environ.get("VIRTUAL_ENV"))
print(os.environ.get("PATH"))
print(os.pathsep.join(sys.path))
import pydoc_test
print(pydoc_test.__file__)
""".format(
str(activator_at)
)
)
script_path = tmp_path / "test.py"
script_path.write_text(script)
try:
raw = subprocess.check_output(
[sys.executable, str(script_path)], stderr=subprocess.STDOUT, universal_newlines=True
)
out = re.sub(r"pydev debugger: process \d+ is connecting\n\n", "", raw, re.M).strip().split("\n")
assert out[0] == "None"
assert out[1] == start_path
prev_sys_path = out[2].split(os.path.pathsep)
assert out[3] == clean_python[0] # virtualenv set as the activated env
# PATH updated with activated
assert out[4].endswith(start_path)
assert out[4][: -len(start_path)].split(os.pathsep) == [clean_python[1], ""]
# sys path contains the site package at its start
new_sys_path = out[5].split(os.path.pathsep)
assert new_sys_path[-len(prev_sys_path) :] == prev_sys_path
extra_start = new_sys_path[0 : -len(prev_sys_path)]
assert len(extra_start) == 1
assert extra_start[0].startswith(clean_python[0])
assert tmp_path.__class__(extra_start[0]).exists()
# manage to import from activate site package
assert os.path.realpath(out[6]) == os.path.realpath(str(clean_python[2]))
except subprocess.CalledProcessError as exception:
assert not exception.returncode, exception.output
def test_activate_this_no_file(clean_python, tmp_path, monkeypatch):
activator = tmp_path.__class__(clean_python[1]) / "activate_this.py"
assert activator.exists()
try:
subprocess.check_output(
[sys.executable, "-c", "exec(open({!r}).read())".format(str(activator))],
stderr=subprocess.STDOUT,
universal_newlines=True,
)
raise RuntimeError("this should not happen")
except subprocess.CalledProcessError as exception:
out = re.sub(r"pydev debugger: process \d+ is connecting\n\n", "", exception.output, re.M).strip()
assert "You must use exec(open(this_file).read(), {'__file__': this_file}))" in out, out

View File

@ -0,0 +1,236 @@
from __future__ import absolute_import, unicode_literals
import os
import pipes
import re
import subprocess
import sys
from os.path import dirname, join, normcase, realpath
import pytest
import six
import virtualenv
IS_INSIDE_CI = "CI_RUN" in os.environ
def need_executable(name, check_cmd):
"""skip running this locally if executable not found, unless we're inside the CI"""
def wrapper(fn):
fn = getattr(pytest.mark, name)(fn)
if not IS_INSIDE_CI:
# locally we disable, so that contributors don't need to have everything setup
# noinspection PyBroadException
try:
fn.version = subprocess.check_output(check_cmd, env=get_env())
except Exception as exception:
return pytest.mark.skip(reason="{} is not available due {}".format(name, exception))(fn)
return fn
return wrapper
def requires(on):
def wrapper(fn):
return need_executable(on.cmd.replace(".exe", ""), on.check)(fn)
return wrapper
def norm_path(path):
# python may return Windows short paths, normalize
path = realpath(path)
if virtualenv.IS_WIN:
from ctypes import create_unicode_buffer, windll
buffer_cont = create_unicode_buffer(256)
get_long_path_name = windll.kernel32.GetLongPathNameW
get_long_path_name(six.text_type(path), buffer_cont, 256) # noqa: F821
result = buffer_cont.value
else:
result = path
return normcase(result)
class Activation(object):
cmd = ""
extension = "test"
invoke_script = []
command_separator = os.linesep
activate_cmd = "source"
activate_script = ""
check_has_exe = []
check = []
env = {}
also_test_error_if_not_sourced = False
def __init__(self, activation_env, tmp_path):
self.home_dir = activation_env[0]
self.bin_dir = activation_env[1]
self.path = tmp_path
def quote(self, s):
return pipes.quote(s)
def python_cmd(self, cmd):
return "{} -c {}".format(self.quote(virtualenv.EXPECTED_EXE), self.quote(cmd))
def python_script(self, script):
return "{} {}".format(self.quote(virtualenv.EXPECTED_EXE), self.quote(script))
def print_python_exe(self):
return self.python_cmd("import sys; print(sys.executable)")
def print_os_env_var(self, var):
val = '"{}"'.format(var)
return self.python_cmd("import os; print(os.environ.get({}, None))".format(val))
def __call__(self, monkeypatch):
absolute_activate_script = norm_path(join(self.bin_dir, self.activate_script))
commands = [
self.print_python_exe(),
self.print_os_env_var("VIRTUAL_ENV"),
self.activate_call(absolute_activate_script),
self.print_python_exe(),
self.print_os_env_var("VIRTUAL_ENV"),
# pydoc loads documentation from the virtualenv site packages
"pydoc -w pydoc_test",
"deactivate",
self.print_python_exe(),
self.print_os_env_var("VIRTUAL_ENV"),
"", # just finish with an empty new line
]
script = self.command_separator.join(commands)
test_script = self.path / "script.{}".format(self.extension)
test_script.write_text(script)
assert test_script.exists()
monkeypatch.chdir(str(self.path))
invoke_shell = self.invoke_script + [str(test_script)]
monkeypatch.delenv(str("VIRTUAL_ENV"), raising=False)
# in case the tool is provided by the dev environment (e.g. xonosh)
env = get_env()
env.update(self.env)
try:
raw = subprocess.check_output(invoke_shell, universal_newlines=True, stderr=subprocess.STDOUT, env=env)
except subprocess.CalledProcessError as exception:
assert not exception.returncode, exception.output
out = re.sub(r"pydev debugger: process \d+ is connecting\n\n", "", raw, re.M).strip().split("\n")
# pre-activation
assert out[0], raw
assert out[1] == "None", raw
# post-activation
exe = "{}.exe".format(virtualenv.EXPECTED_EXE) if virtualenv.IS_WIN else virtualenv.EXPECTED_EXE
assert norm_path(out[2]) == norm_path(join(self.bin_dir, exe)), raw
assert norm_path(out[3]) == norm_path(str(self.home_dir)).replace("\\\\", "\\"), raw
assert out[4] == "wrote pydoc_test.html"
content = self.path / "pydoc_test.html"
assert content.exists(), raw
# post deactivation, same as before
assert out[-2] == out[0], raw
assert out[-1] == "None", raw
if self.also_test_error_if_not_sourced:
invoke_shell = self.invoke_script + [absolute_activate_script]
with pytest.raises(subprocess.CalledProcessError) as c:
subprocess.check_output(invoke_shell, stderr=subprocess.STDOUT, env=env)
assert c.value.returncode, c
def activate_call(self, script):
return "{} {}".format(pipes.quote(self.activate_cmd), pipes.quote(script)).strip()
def get_env():
env = os.environ.copy()
env[str("PATH")] = os.pathsep.join([dirname(sys.executable)] + env.get(str("PATH"), str("")).split(os.pathsep))
return env
class BashActivation(Activation):
cmd = "bash.exe" if virtualenv.IS_WIN else "bash"
invoke_script = [cmd]
extension = "sh"
activate_script = "activate"
check = [cmd, "--version"]
also_test_error_if_not_sourced = True
@pytest.mark.skipif(sys.platform == "win32", reason="no sane way to provision bash on Windows yet")
@requires(BashActivation)
def test_bash(clean_python, monkeypatch, tmp_path):
BashActivation(clean_python, tmp_path)(monkeypatch)
class CshActivation(Activation):
cmd = "csh.exe" if virtualenv.IS_WIN else "csh"
invoke_script = [cmd]
extension = "csh"
activate_script = "activate.csh"
check = [cmd, "--version"]
@pytest.mark.skipif(sys.platform == "win32", reason="no sane way to provision csh on Windows yet")
@requires(CshActivation)
def test_csh(clean_python, monkeypatch, tmp_path):
CshActivation(clean_python, tmp_path)(monkeypatch)
class FishActivation(Activation):
cmd = "fish.exe" if virtualenv.IS_WIN else "fish"
invoke_script = [cmd]
extension = "fish"
activate_script = "activate.fish"
check = [cmd, "--version"]
@pytest.mark.skipif(sys.platform == "win32", reason="no sane way to provision fish on Windows yet")
@requires(FishActivation)
def test_fish(clean_python, monkeypatch, tmp_path):
FishActivation(clean_python, tmp_path)(monkeypatch)
class PowershellActivation(Activation):
cmd = "powershell.exe" if virtualenv.IS_WIN else "pwsh"
extension = "ps1"
invoke_script = [cmd, "-File"]
activate_script = "activate.ps1"
activate_cmd = "."
check = [cmd, "-c", "$PSVersionTable"]
def quote(self, s):
"""powershell double double quote needed for quotes within single quotes"""
return pipes.quote(s).replace('"', '""')
@requires(PowershellActivation)
def test_powershell(clean_python, monkeypatch, tmp_path):
PowershellActivation(clean_python, tmp_path)(monkeypatch)
class XonoshActivation(Activation):
cmd = "xonsh"
extension = "xsh"
invoke_script = [sys.executable, "-m", "xonsh"]
activate_script = "activate.xsh"
check = [sys.executable, "-m", "xonsh", "--version"]
env = {"XONSH_DEBUG": "1", "XONSH_SHOW_TRACEBACK": "True"}
def activate_call(self, script):
return "{} {}".format(self.activate_cmd, repr(script)).strip()
@pytest.mark.skipif(sys.version_info < (3, 5), reason="xonosh requires Python 3.5 at least")
@requires(XonoshActivation)
def test_xonosh(clean_python, monkeypatch, tmp_path):
XonoshActivation(clean_python, tmp_path)(monkeypatch)

View File

@ -0,0 +1,440 @@
"""test that prompt behavior is correct in supported shells"""
from __future__ import absolute_import, unicode_literals
import os
import subprocess
import sys
from textwrap import dedent
import pytest
import virtualenv
from virtualenv import IS_DARWIN, IS_WIN
try:
from pathlib import Path
except ImportError:
from pathlib2 import Path
VIRTUAL_ENV_DISABLE_PROMPT = "VIRTUAL_ENV_DISABLE_PROMPT"
# This must match the DEST_DIR provided in the ../conftest.py:clean_python fixture
ENV_DEFAULT = "env"
# This can be anything
ENV_CUSTOM = "envy"
# Standard prefix, surround the env name in parentheses and separate by a space
PREFIX_DEFAULT = "({}) ".format(ENV_DEFAULT)
# Arbitrary prefix for the environment that's provided a 'prompt' arg
PREFIX_CUSTOM = "---ENV---"
# Temp script filename template: {shell}.script.(normal|suppress).(default|custom)[extension]
SCRIPT_TEMPLATE = "{}.script.{}.{}{}"
# Temp output filename template: {shell}.out.(normal|suppress).(default|custom)
OUTPUT_TEMPLATE = "{}.out.{}.{}"
# For skipping shells not installed by default if absent on a contributor's system
IS_INSIDE_CI = "CI_RUN" in os.environ
# Py2 doesn't like unicode in the environment
def env_compat(string):
return string.encode("utf-8") if sys.version_info.major < 3 else string
class ShellInfo(object):
"""Parent class for shell information for prompt testing."""
# Typo insurance
__slots__ = []
# Equality check based on .name, but only if both are not None
def __eq__(self, other):
if type(self) != type(other):
return False
if self.name is None or other.name is None:
return False
return self.name == other.name
# Helper formatting string
@property
def platform_incompat_msg(self):
return "No sane provision for {} on {{}} yet".format(self.name)
# Each shell must specify
name = None
avail_cmd = None
execute_cmd = None
prompt_cmd = None
activate_script = None
# Default values defined here
# 'preamble_cmd' *MUST NOT* emit anything to stdout!
testscript_extension = ""
preamble_cmd = ""
activate_cmd = "source "
deactivate_cmd = "deactivate"
clean_env_update = {}
# Skip check function; must be specified per-shell
platform_check_skip = None
# Test assert method for comparing activated prompt to deactivated.
# Default defined, but can be overridden per-shell. Takes the captured
# lines of output as the lone argument.
def overall_prompt_test(self, lines, prefix):
"""Perform all tests on (de)activated prompts.
From a Python 3 perspective, 'lines' is expected to be *bytes*,
and 'prefix' is expected to be *str*.
Happily, this all seems to translate smoothly enough to 2.7.
"""
# Prompts before activation and after deactivation should be identical.
assert lines[1] == lines[3], lines
# The .partition here operates on the environment marker text expected to occur
# in the prompt. A non-empty 'env_marker' thus tests that the correct marker text
# has been applied into the prompt string.
before, env_marker, after = lines[2].partition(prefix.encode("utf-8"))
assert env_marker != b"", lines
# Some shells need custom activated-prompt tests, so this is split into
# its own submethod.
self.activated_prompt_test(lines, after)
def activated_prompt_test(self, lines, after):
"""Perform just the check for the deactivated prompt contents in the activated prompt text.
The default is a strict requirement that the portion of the activated prompt following the environment
marker must exactly match the non-activated prompt.
Some shells require weaker tests, due to idiosyncrasies.
"""
assert after == lines[1], lines
class BashInfo(ShellInfo):
name = "bash"
avail_cmd = "bash -c 'echo foo'"
execute_cmd = "bash"
prompt_cmd = 'echo "$PS1"'
activate_script = "activate"
def platform_check_skip(self):
if IS_WIN:
return self.platform_incompat_msg.format(sys.platform)
class FishInfo(ShellInfo):
name = "fish"
avail_cmd = "fish -c 'echo foo'"
execute_cmd = "fish"
prompt_cmd = "fish_prompt; echo ' '"
activate_script = "activate.fish"
# Azure Devops doesn't set a terminal type, which breaks fish's colorization
# machinery in a way that spuriously fouls the activation script.
clean_env_update = {"TERM": "linux"}
def platform_check_skip(self):
if IS_WIN:
return self.platform_incompat_msg.format(sys.platform)
def activated_prompt_test(self, lines, after):
"""Require a looser match here, due to interposed ANSI color codes.
This construction allows coping with the messiness of fish's ANSI codes for colorizing.
It's not as rigorous as I would like---it doesn't ensure no space is inserted between
a custom env prompt (argument to --prompt) and the base prompt---but it does provide assurance as
to the key pieces of content that should be present.
"""
assert lines[1] in after, lines
class CshInfo(ShellInfo):
name = "csh"
avail_cmd = "csh -c 'echo foo'"
execute_cmd = "csh"
prompt_cmd = r"set | grep -E 'prompt\s' | sed -E 's/^prompt\s+(.*)$/\1/'"
activate_script = "activate.csh"
# csh defaults to an unset 'prompt' in non-interactive shells
preamble_cmd = "set prompt=%"
def platform_check_skip(self):
if IS_WIN:
return self.platform_incompat_msg.format(sys.platform)
def activated_prompt_test(self, lines, after):
"""Test with special handling on MacOS, which does funny things to stdout under (t)csh."""
if IS_DARWIN:
# Looser assert for (t)csh on MacOS, which prepends extra text to
# what gets sent to stdout
assert lines[1].endswith(after), lines
else:
# Otherwise, use the rigorous default
# Full 2-arg form for super() used for 2.7 compat
super(CshInfo, self).activated_prompt_test(lines, after)
class XonshInfo(ShellInfo):
name = "xonsh"
avail_cmd = "xonsh -c 'echo foo'"
execute_cmd = "xonsh"
prompt_cmd = "print(__xonsh__.shell.prompt)"
activate_script = "activate.xsh"
# Sets consistent initial state
preamble_cmd = (
"$VIRTUAL_ENV = ''; $PROMPT = '{env_name}$ '; "
"$PROMPT_FIELDS['env_prefix'] = '('; $PROMPT_FIELDS['env_postfix'] = ') '"
)
@staticmethod
def platform_check_skip():
if IS_WIN:
return "Provisioning xonsh on windows is unreliable"
if sys.version_info < (3, 5):
return "xonsh requires Python 3.5 at least"
class CmdInfo(ShellInfo):
name = "cmd"
avail_cmd = "echo foo"
execute_cmd = ""
prompt_cmd = "echo %PROMPT%"
activate_script = "activate.bat"
testscript_extension = ".bat"
preamble_cmd = "@echo off & set PROMPT=$P$G" # For consistent initial state
activate_cmd = "call "
deactivate_cmd = "call deactivate"
def platform_check_skip(self):
if not IS_WIN:
return self.platform_incompat_msg.format(sys.platform)
class PoshInfo(ShellInfo):
name = "powershell"
avail_cmd = "powershell 'echo foo'"
execute_cmd = "powershell -File "
prompt_cmd = "prompt"
activate_script = "activate.ps1"
testscript_extension = ".ps1"
activate_cmd = ". "
def platform_check_skip(self):
if not IS_WIN:
return self.platform_incompat_msg.format(sys.platform)
SHELL_INFO_LIST = [BashInfo(), FishInfo(), CshInfo(), XonshInfo(), CmdInfo(), PoshInfo()]
@pytest.fixture(scope="module")
def posh_execute_enabled(tmp_path_factory):
"""Return check value for whether Powershell script execution is enabled.
Posh may be available interactively, but the security settings may not allow
execution of script files.
# Enable with: PS> Set-ExecutionPolicy -scope currentuser -ExecutionPolicy Bypass -Force;
# Disable with: PS> Set-ExecutionPolicy -scope currentuser -ExecutionPolicy Restricted -Force;
"""
if not IS_WIN:
return False
test_ps1 = tmp_path_factory.mktemp("posh_test") / "test.ps1"
with open(str(test_ps1), "w") as f:
f.write("echo 'foo bar baz'\n")
out = subprocess.check_output(["powershell", "-File", "{}".format(str(test_ps1))], shell=True)
return b"foo bar baz" in out
@pytest.fixture(scope="module")
def shell_avail(posh_execute_enabled):
"""Generate mapping of ShellInfo.name strings to bools of shell availability."""
retvals = {si.name: subprocess.call(si.avail_cmd, shell=True) for si in SHELL_INFO_LIST}
avails = {si.name: retvals[si.name] == 0 for si in SHELL_INFO_LIST}
# Extra check for whether powershell scripts are enabled
avails[PoshInfo().name] = avails[PoshInfo().name] and posh_execute_enabled
return avails
@pytest.fixture(scope="module")
def custom_prompt_root(tmp_path_factory):
"""Provide Path to root with default and custom venvs created."""
root = tmp_path_factory.mktemp("custom_prompt")
virtualenv.create_environment(
str(root / ENV_CUSTOM), prompt=PREFIX_CUSTOM, no_setuptools=True, no_pip=True, no_wheel=True
)
_, _, _, bin_dir = virtualenv.path_locations(str(root / ENV_DEFAULT))
bin_dir_name = os.path.split(bin_dir)[-1]
return root, bin_dir_name
@pytest.fixture(scope="module")
def clean_python_root(clean_python):
root = Path(clean_python[0]).resolve().parent
bin_dir_name = os.path.split(clean_python[1])[-1]
return root, bin_dir_name
@pytest.fixture(scope="module")
def get_work_root(clean_python_root, custom_prompt_root):
def pick_root(env):
if env == ENV_DEFAULT:
return clean_python_root
elif env == ENV_CUSTOM:
return custom_prompt_root
else:
raise ValueError("Invalid test virtualenv")
return pick_root
@pytest.fixture(scope="function")
def clean_env():
"""Provide a fresh copy of the shell environment.
VIRTUAL_ENV_DISABLE_PROMPT is always removed, if present, because
the prompt tests assume it to be unset.
"""
clean_env = os.environ.copy()
clean_env.pop(env_compat(VIRTUAL_ENV_DISABLE_PROMPT), None)
return clean_env
@pytest.mark.parametrize("shell_info", SHELL_INFO_LIST, ids=[i.name for i in SHELL_INFO_LIST])
@pytest.mark.parametrize("env", [ENV_DEFAULT, ENV_CUSTOM], ids=["default", "custom"])
@pytest.mark.parametrize(("value", "disable"), [("", False), ("0", True), ("1", True)])
def test_suppressed_prompt(shell_info, shell_avail, env, value, disable, get_work_root, clean_env):
"""Confirm non-empty VIRTUAL_ENV_DISABLE_PROMPT suppresses prompt changes on activate."""
skip_test = shell_info.platform_check_skip()
if skip_test:
pytest.skip(skip_test)
if not IS_INSIDE_CI and not shell_avail[shell_info.name]:
pytest.skip(
"Shell '{}' not provisioned{}".format(
shell_info.name, " - is Powershell script execution disabled?" if shell_info == PoshInfo() else ""
)
)
script_name = SCRIPT_TEMPLATE.format(shell_info.name, "suppress", env, shell_info.testscript_extension)
output_name = OUTPUT_TEMPLATE.format(shell_info.name, "suppress", env)
clean_env.update({env_compat(VIRTUAL_ENV_DISABLE_PROMPT): env_compat(value)})
work_root = get_work_root(env)
# The extra "{prompt}" here copes with some oddity of xonsh in certain emulated terminal
# contexts: xonsh can dump stuff into the first line of the recorded script output,
# so we have to include a dummy line of output that can get munged w/o consequence.
with open(str(work_root[0] / script_name), "w") as f:
f.write(
dedent(
"""\
{preamble}
{prompt}
{prompt}
{act_cmd}{env}/{bindir}/{act_script}
{prompt}
""".format(
env=env,
act_cmd=shell_info.activate_cmd,
preamble=shell_info.preamble_cmd,
prompt=shell_info.prompt_cmd,
act_script=shell_info.activate_script,
bindir=work_root[1],
)
)
)
command = "{} {} > {}".format(shell_info.execute_cmd, script_name, output_name)
assert 0 == subprocess.call(command, cwd=str(work_root[0]), shell=True, env=clean_env)
with open(str(work_root[0] / output_name), "rb") as f:
text = f.read()
lines = text.split(b"\n")
# Is the prompt suppressed based on the env var value?
assert (lines[1] == lines[2]) == disable, text
@pytest.mark.parametrize("shell_info", SHELL_INFO_LIST, ids=[i.name for i in SHELL_INFO_LIST])
@pytest.mark.parametrize(["env", "prefix"], [(ENV_DEFAULT, PREFIX_DEFAULT), (ENV_CUSTOM, PREFIX_CUSTOM)])
def test_activated_prompt(shell_info, shell_avail, env, prefix, get_work_root, clean_env):
"""Confirm prompt modification behavior with and without --prompt specified."""
skip_test = shell_info.platform_check_skip()
if skip_test:
pytest.skip(skip_test)
if not IS_INSIDE_CI and not shell_avail[shell_info.name]:
pytest.skip(
"Shell '{}' not provisioned".format(shell_info.name)
+ (" - is Powershell script execution disabled?" if shell_info == PoshInfo() else "")
)
for k, v in shell_info.clean_env_update.items():
clean_env.update({env_compat(k): env_compat(v)})
script_name = SCRIPT_TEMPLATE.format(shell_info.name, "normal", env, shell_info.testscript_extension)
output_name = OUTPUT_TEMPLATE.format(shell_info.name, "normal", env)
work_root = get_work_root(env)
# The extra "{prompt}" here copes with some oddity of xonsh in certain emulated terminal
# contexts: xonsh can dump stuff into the first line of the recorded script output,
# so we have to include a dummy line of output that can get munged w/o consequence.
with open(str(work_root[0] / script_name), "w") as f:
f.write(
dedent(
"""\
{preamble}
{prompt}
{prompt}
{act_cmd}{env}/{bindir}/{act_script}
{prompt}
{deactivate}
{prompt}
""".format(
env=env,
act_cmd=shell_info.activate_cmd,
deactivate=shell_info.deactivate_cmd,
preamble=shell_info.preamble_cmd,
prompt=shell_info.prompt_cmd,
act_script=shell_info.activate_script,
bindir=work_root[1],
)
)
)
command = "{} {} > {}".format(shell_info.execute_cmd, script_name, output_name)
assert 0 == subprocess.call(command, cwd=str(work_root[0]), shell=True, env=clean_env)
with open(str(work_root[0] / output_name), "rb") as f:
lines = f.read().split(b"\n")
shell_info.overall_prompt_test(lines, prefix)

View File

@ -0,0 +1,139 @@
from __future__ import absolute_import, unicode_literals
import os
import pipes
import subprocess
import sys
import textwrap
import pytest
import virtualenv
try:
from pathlib import Path
except ImportError:
from pathlib2 import Path
ROOT_DIR = Path(__file__).parents[1]
@pytest.fixture(scope="session")
def clean_python(tmp_path_factory):
path = tmp_path_factory.mktemp("activation-test-env")
prev_cwd = os.getcwd()
try:
os.chdir(str(path))
home_dir, _, __, bin_dir = virtualenv.path_locations(str(path / "env"))
virtualenv.create_environment(home_dir, no_pip=True, no_setuptools=True, no_wheel=True)
site_packages = subprocess.check_output(
[
os.path.join(bin_dir, virtualenv.EXPECTED_EXE),
"-c",
"from distutils.sysconfig import get_python_lib; print(get_python_lib())",
],
universal_newlines=True,
).strip()
pydoc_test = path.__class__(site_packages) / "pydoc_test.py"
pydoc_test.write_text('"""This is pydoc_test.py"""')
finally:
os.chdir(str(prev_cwd))
yield home_dir, bin_dir, pydoc_test
@pytest.fixture()
def sdist(tmp_path):
"""make assertions on what we package"""
import tarfile
path = os.environ.get("TOX_PACKAGE")
if path is not None:
dest_path = tmp_path / "sdist"
dest_path.mkdir()
prev = os.getcwd()
try:
os.chdir(str(dest_path))
tar = tarfile.open(path, "r:gz")
tar.extractall()
return next(dest_path.iterdir())
finally:
os.chdir(prev)
return None
@pytest.fixture(scope="session")
def wheel(tmp_path_factory):
"""test that we can create a virtual environment by feeding to a clean python the wheels content"""
dest_path = tmp_path_factory.mktemp("wheel")
env = os.environ.copy()
try:
subprocess.check_output(
[sys.executable, "-m", "pip", "wheel", "-w", str(dest_path), "--no-deps", str(ROOT_DIR)],
universal_newlines=True,
stderr=subprocess.STDOUT,
env=env,
)
except subprocess.CalledProcessError as exception:
assert not exception.returncode, exception.output
wheels = list(dest_path.glob("*.whl"))
assert len(wheels) == 1
wheel = wheels[0]
return wheel
@pytest.fixture()
def extracted_wheel(tmp_path, wheel):
dest_path = tmp_path / "wheel-extracted"
import zipfile
with zipfile.ZipFile(str(wheel), "r") as zip_ref:
zip_ref.extractall(str(dest_path))
return dest_path
def _call(cmd, env=None, stdin=None, allow_fail=False, shell=False, **kwargs):
env = os.environ if env is None else env
process = subprocess.Popen(
cmd,
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
env=env,
shell=shell,
**kwargs
)
out, err = process.communicate(input=stdin)
if allow_fail is False:
msg = textwrap.dedent(
"""
cmd:
{}
out:
{}
err:
{}
env:
{}
"""
).format(
cmd if shell else " ".join(pipes.quote(str(i)) for i in cmd),
out,
err,
os.linesep.join("{}={!r}".format(k, v) for k, v in env.items()),
)
msg = msg.lstrip()
assert process.returncode == 0, msg
return out, err
else:
return process.returncode, out, err
@pytest.fixture(scope="session")
def call_subprocess():
return _call

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA0D+NxiOUkvWp45C75ZmCdzl3Cqu09MV9GvVjv5vU2So92pJI
sMmZDavteLEdA1g/T3Wzh6vop0NGXskrGIQ0QXPcnbtJtWH2n+R8/N4xlFliEwX+
JZOrzWFeZGzVJd7VKr2ncO/B5VGIYPB+HTD3VYzm2ACZnyB7NvTJXM/IH0x19TI8
Bad3rNNX3XnL0c6N8Zd9Hqyj25ciNSiY8a/TnvOEtLw1yo1HNUX6V5xgI5fslDXl
t3tKg3zmuGZXSLhYMjEN4q7NOdI8qW7mQrabCvyiIDCxJeLHdL+ks6FWmoHL9j5r
vHq8lyaMM28d/928KSlZtNpwxh5nhHEChLlf8QIDAQABAoIBAQCxII13LYZO5ZNm
ExIuvT5iKEeflOLqmxvJFVWNgX8uY6aOxYP8ksyS+1yWHped466d6HAWgtr1gdxV
/OeiB7jmvyS0KLwOAlAiOdcxwdAL7Wbk5WEBFzS3EQ2Xf5ZgisNngj7saZHTemD0
iznJnH+TjbA/o2sHFTqYSOcJAVanfviqCxH/3xKPAS9vnFPYcpPr8xrQaR2sX6Zy
aZUNVE4udSl3+GqMhMeq1dxssua4PQVsplwIJbY3KUIQIkXNLR8Zal8ygi5HI29U
q+PPiM89O9lgzUz246x1ruNKIl+zgOQsn1yg0Wx+ho1b5kVE4yqi58tVPCN/Bc8H
lWai906RAoGBAPjFWDnrBo5PBVuXOYmPvo10J9n2iIOKOBr3V4OlUb46LcRk19E9
nV+zidoNKxTaB+g7dlKqYpvOnZ0MUKLPPE1G1U3RlKO+qVhnQ/Pf1N1e88ojCWDu
pFWezwOAO/BJGKQk7sYqMz47hfnLRydeipMv3ASEhKr1rP/b3M1ICrd1AoGBANZM
wOHm0fd87w3WS8eBivI3+W1mL6mHzNJ20G3OM1kUPcbUBzqocwYp3AUXZmO6X8GC
RSmkQ7U81yA5GcdhPIlGa8emSuYPyKBAjgX3fOGgZGNMrcmc+o+uRdyzfxKR1Oph
nnLKj2f7xIXGgGs6gqv00omLEScZ4oqBL+I4ovMNAoGBAM9fem81as6gMqAqDI2O
ZNL3u+ym5R95zdE01B/qZJzFVLd9NKa4zQIk4MoC5iHIqoS9ZKH+ZJrq/loXFPTS
+bqVTGRFS7m/ytzloDCgKoqqh2C+GihSZmz1KC4L7GseE8to+h34uaSr67/R4yt/
VNbjM24UpZ75ks/qEEKTRlOtAoGAad6nV7MJvgO5shNRgrGL7Fgc4KAgIdfWJ4/N
LsI0+egXEPhEzgTUNpJNgTJrQg+cKORruMPPM2VoPiIXizmNh6ADtTGBRSE9E3Zw
85+t0WXE0o3aOYVU/9Cv8PW4bHshPd2WQs2xhUSLdS942ACi98LOlGbgxXlzQsvJ
1S/3yK0CgYEAwu+gAfwpuJSSk7yyiUjIh6PA00lZnuxgj2AeqS2RSRk+YkV8ZJOP
MhoZpJv+OCrAQFY9ybptJfbGyJQNkpkRHt82aNbevFxly2tTVT+zbeUbeMnX5qn4
nOCaAc9u4QDTrSE3DS/JSWelv4gjq782THmWSSZfrwS/qV6KrhqZfXk=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgIJAJyQNZE5SUeEMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAlJVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwIBcNMTkwMTExMTkwNjM4WhgPMjI5MjEwMjYxOTA2Mzha
MEUxCzAJBgNVBAYTAlJVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ
bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDQP43GI5SS9anjkLvlmYJ3OXcKq7T0xX0a9WO/m9TZKj3akkiwyZkN
q+14sR0DWD9PdbOHq+inQ0ZeySsYhDRBc9ydu0m1Yfaf5Hz83jGUWWITBf4lk6vN
YV5kbNUl3tUqvadw78HlUYhg8H4dMPdVjObYAJmfIHs29Mlcz8gfTHX1MjwFp3es
01fdecvRzo3xl30erKPblyI1KJjxr9Oe84S0vDXKjUc1RfpXnGAjl+yUNeW3e0qD
fOa4ZldIuFgyMQ3irs050jypbuZCtpsK/KIgMLEl4sd0v6SzoVaagcv2Pmu8eryX
Jowzbx3/3bwpKVm02nDGHmeEcQKEuV/xAgMBAAGjUDBOMB0GA1UdDgQWBBTYiCMT
/U1XaXKam/gNiQK28/f1jzAfBgNVHSMEGDAWgBTYiCMT/U1XaXKam/gNiQK28/f1
jzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBll3abJLJxh8LNAz/B
xpPly54SttwEqDeFC6y35ilgq53aNAu5Smx+ka9OotnPcfuUEIuOf7kWre02OuAU
FCEcViXLM9+NWMVKTD+ZQ8H0VL0GMJOidt/FReTSixawJY1YB6HhFwI1yVd+x8+l
vwyqoHNz/Uk6unsHIAJk5Esj3IuiYwOw6KmsiZv9IsIX7IXv3g6eKYC7162ArLyw
8nPFWcKJTAHFzmGhvrS6vV08mv+6Helgp/B3OFm/OqDm2LwASIUDlzQjdeowNo9Z
z6O/JNjoBLCMAVm/an/zONUb/XZXsw3CAYAta3fuRT7FptMBIJCtMuVgrmzzG79X
PcF/
-----END CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDHDCCAgQCCQD8eKhHCWYb1TANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJS
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMCAXDTE5MDExMTE5MDc0N1oYDzIyOTIxMDI2MTkwNzQ3WjBZMQsw
CQYDVQQGEwJSVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu
ZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDr/u2BS0mKqz+rLwyd79LrcvBZOpXoRVib
lE2zhz9ZBlQZ/nmSg40QPZqOsgrGZKYFMfLY1AYNpKCJYe4lBQ2YqU1Jac0WYXdh
WEfEKW1hYCsuY9wpz1kVfCAfUD2+1/hOBd2ghgpx3YJgkjIPUeywpalOxD+1j+8r
RjfouVl4kB9UOsRoJzZHP2L6yzCABeoZgVgupkJNHx1KMSYyETLvwxni/FE1lmFA
kxdRV7B8YcWlG+0ewl23KTdMtxtfzUJ+OrShs5fl1UoG8BqRxLVxf889cfkYy6aF
q3tKbRtAgIpmET0UoYzrBbWIVoKgqYnASTFR/hXfGhozN8chStW1AgMBAAEwDQYJ
KoZIhvcNAQELBQADggEBAC/2/sdFcsPSv48dk5GPqutOhQnFDH4qoW9B4cCQXISD
GZ4hDme/RDB/cIgpHBWrtrSq0893d7cXl57aMWjDJmWH1iXTFJ5h9mYhvaWZekR0
t4D0ZJYVhTiSOdavMc50payWYuTwaUqeXHPkOKKNgGrlcVV4n+tkQq/dvFBZXA8b
ql4x6PmU/Oqf0dY/f5PzgNb1rEHhsdqpJEZdjLsFFKdJX0ikaGak13iEDPR3uEZt
/Eu8VOVGuMwK8+Q4/AUctsfh03wqP82RBlCWTk5eTe34y0dNui3hc+oWIjLf6+pc
xjEnh5EWq/Hf4AEUT6PwP3m3ZmxeUlWMMx6GA27ovrc=
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDr/u2BS0mKqz+r
Lwyd79LrcvBZOpXoRViblE2zhz9ZBlQZ/nmSg40QPZqOsgrGZKYFMfLY1AYNpKCJ
Ye4lBQ2YqU1Jac0WYXdhWEfEKW1hYCsuY9wpz1kVfCAfUD2+1/hOBd2ghgpx3YJg
kjIPUeywpalOxD+1j+8rRjfouVl4kB9UOsRoJzZHP2L6yzCABeoZgVgupkJNHx1K
MSYyETLvwxni/FE1lmFAkxdRV7B8YcWlG+0ewl23KTdMtxtfzUJ+OrShs5fl1UoG
8BqRxLVxf889cfkYy6aFq3tKbRtAgIpmET0UoYzrBbWIVoKgqYnASTFR/hXfGhoz
N8chStW1AgMBAAECggEAVpw0piLvVokK0NRvmPcPPYHtW5H4uknY/yAqdBzKzu1X
qEKQc4j8GF3Df2MwOSdvFrECIzmNDyzADit2rvdvyfs4dhzyO6iBm6Q+kmtxzS7y
KhBUGLQUSaJIV7WnM4cnhdr5P5Rx+OAGnVKKNL0oVJw3ysSTbRrp98PJeQutHmVx
7wIBePrmrIeRS3uESty3rqSyypKO6DYhIwsV3yzsr0kad+o6MT1gb/EB7qEj5uNX
E81lnhoHlYtPJujJUCucQmfqKX7LRSq7bEfxFcJXOwKB2/2ILT3tXBTlYlKuvC43
TaajaaUTSBFhL9zuYv1XWCyX/MXXxA27SvaBIjFE8QKBgQD3I4vGQ94juCCNaUT8
dPSBn+dnkfqKdxH8WF6q2KdsdYFbFEfW7/rY5jSRQMu6VF/AXiJFh5amQiDUnfWb
QDmtyqGk2kb1g5gUm6plRPL3P3pQ4x1FVtJgVvxV26rQxTV6Bv6zM8SoJUMZJaEz
/z8QX5/dF7vlFGmy8LH4efYsXwKBgQD0dRnvQGFtwnD7xI/0ihltdogrzFb6sOpU
vsXporJS19vjfunCJKjXL9JvFAw2Gk6XUQ9wCUYjLMu1ovahiLm5FMsfhDtTMhvS
9HQvV8RdMk0NSorP/2LfpEsUqqkTXB5dxelbmNJeLr3fK+9azsK0wLXCT3vUo/kV
uPISrh32awKBgEn9jWplhUtCZBSSUMIYrd9lJV2/ubfc4DihqG4UAUQahgjjsIJs
RLjNay2Vrajye9xXEoGoj3TlVXjydcbuWpZqlSyK4TW+GTkKReCd3PQjQBaZeHj6
/m8ze8akxqZMdK89CuJR/G2vAkC0IGg14gaf6nfCFFIIY4DcSRwwP4CXAoGAantz
r46oocnXsyNc3VUmXFMMX5+jp5FWkVGEHg/7gzB5nK/UnPehABLZo/7kjtCIuUra
4Z94iKvjlBwHODe5RpBzJihQOx4RlqNa1KBzbXEStR5qNs30wJvtBHSOL1up8ojZ
7Ec2I0ZS+JpHqZN0po1m3twGgYpnXnnwIAjuDj8CgYBJHcoMJCRnuYqvDBJzqZDj
6DAGT60qa6E+p/xkKAmys69Un1KDsnLTYNvV7wivqfve0/2Ja9gg3Neocq39tsTF
rTjeKHO3D8FN3C79diWj65ohrS6vOyhkBroAmOxDQgD7nKQrkyd865qlTNsyGFmC
KEFgzjGWDx2Wk9vUYUxBOg==
-----END PRIVATE KEY-----

View File

@ -1,96 +0,0 @@
#!/bin/sh
set -u
ROOT="$(dirname $0)/.."
VIRTUALENV="${ROOT}/virtualenv.py"
TESTENV="/tmp/test_virtualenv_activate.venv"
rm -rf ${TESTENV}
echo "$0: Creating virtualenv ${TESTENV}..." 1>&2
${VIRTUALENV} ${TESTENV} | tee ${ROOT}/tests/test_activate_output.actual
if ! diff ${ROOT}/tests/test_activate_output.expected ${ROOT}/tests/test_activate_output.actual; then
echo "$0: Failed to get expected output from ${VIRTUALENV}!" 1>&2
exit 1
fi
echo "$0: Created virtualenv ${TESTENV}." 1>&2
echo "$0: Activating ${TESTENV}..." 1>&2
. ${TESTENV}/bin/activate
echo "$0: Activated ${TESTENV}." 1>&2
echo "$0: Checking value of \$VIRTUAL_ENV..." 1>&2
if [ "$VIRTUAL_ENV" != "${TESTENV}" ]; then
echo "$0: Expected \$VIRTUAL_ENV to be set to \"${TESTENV}\"; actual value: \"${VIRTUAL_ENV}\"!" 1>&2
exit 2
fi
echo "$0: \$VIRTUAL_ENV = \"${VIRTUAL_ENV}\" -- OK." 1>&2
echo "$0: Checking output of \$(which python)..." 1>&2
if [ "$(which python)" != "${TESTENV}/bin/python" ]; then
echo "$0: Expected \$(which python) to return \"${TESTENV}/bin/python\"; actual value: \"$(which python)\"!" 1>&2
exit 3
fi
echo "$0: Output of \$(which python) is OK." 1>&2
echo "$0: Checking output of \$(which pip)..." 1>&2
if [ "$(which pip)" != "${TESTENV}/bin/pip" ]; then
echo "$0: Expected \$(which pip) to return \"${TESTENV}/bin/pip\"; actual value: \"$(which pip)\"!" 1>&2
exit 4
fi
echo "$0: Output of \$(which pip) is OK." 1>&2
echo "$0: Checking output of \$(which easy_install)..." 1>&2
if [ "$(which easy_install)" != "${TESTENV}/bin/easy_install" ]; then
echo "$0: Expected \$(which easy_install) to return \"${TESTENV}/bin/easy_install\"; actual value: \"$(which easy_install)\"!" 1>&2
exit 5
fi
echo "$0: Output of \$(which easy_install) is OK." 1>&2
echo "$0: Executing a simple Python program..." 1>&2
TESTENV=${TESTENV} python <<__END__
import os, sys
expected_site_packages = os.path.join(os.environ['TESTENV'], 'lib','python%s' % sys.version[:3], 'site-packages')
site_packages = os.path.join(os.environ['VIRTUAL_ENV'], 'lib', 'python%s' % sys.version[:3], 'site-packages')
assert site_packages == expected_site_packages, 'site_packages did not have expected value; actual value: %r' % site_packages
open(os.path.join(site_packages, 'pydoc_test.py'), 'w').write('"""This is pydoc_test.py"""\n')
__END__
if [ $? -ne 0 ]; then
echo "$0: Python script failed!" 1>&2
exit 6
fi
echo "$0: Execution of a simple Python program -- OK." 1>&2
echo "$0: Testing pydoc..." 1>&2
if ! PAGER=cat pydoc pydoc_test | grep 'This is pydoc_test.py' > /dev/null; then
echo "$0: pydoc test failed!" 1>&2
exit 7
fi
echo "$0: pydoc is OK." 1>&2
echo "$0: Deactivating ${TESTENV}..." 1>&2
deactivate
echo "$0: Deactivated ${TESTENV}." 1>&2
echo "$0: OK!" 1>&2
rm -rf ${TESTENV}

View File

@ -1,2 +0,0 @@
New python executable in /tmp/test_virtualenv_activate.venv/bin/python
Installing setuptools, pip, wheel...done.

View File

@ -0,0 +1,87 @@
from __future__ import absolute_import, unicode_literals
import inspect
import os
import re
import subprocess
import sys
import textwrap
import six
import virtualenv
def bootstrap():
print("startup")
import subprocess
import os
# noinspection PyUnusedLocal
def extend_parser(opt_parse_parser):
print("extend parser with count")
opt_parse_parser.add_option("-c", action="count", dest="count", default=0, help="Count number of times passed")
# noinspection PyUnusedLocal
def adjust_options(options, args):
print("adjust options")
options.count += 1
# noinspection PyUnusedLocal
def after_install(options, home_dir):
print("after install {} with options {}".format(home_dir, options.count))
# noinspection PyUnresolvedReferences
_, _, _, bin_dir = path_locations(home_dir) # noqa: F821
# noinspection PyUnresolvedReferences
print(
"exe at {}".format(
subprocess.check_output(
[os.path.join(bin_dir, EXPECTED_EXE), "-c", "import sys; print(sys.executable)"], # noqa: F821
universal_newlines=True,
)
)
)
def test_bootstrap(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)
extra_code = inspect.getsource(bootstrap)
extra_code = textwrap.dedent(extra_code[extra_code.index("\n") + 1 :])
output = virtualenv.create_bootstrap_script(extra_code)
assert extra_code in output
if six.PY2:
output = output.decode()
write_at = tmp_path / "blog-bootstrap.py"
write_at.write_text(output)
try:
monkeypatch.chdir(tmp_path)
cmd = [
sys.executable,
str(write_at),
"--no-download",
"--no-pip",
"--no-wheel",
"--no-setuptools",
"-ccc",
"-qqq",
"env",
]
raw = subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT)
out = re.sub(r"pydev debugger: process \d+ is connecting\n\n", "", raw, re.M).strip().split("\n")
_, _, _, bin_dir = virtualenv.path_locations(str(tmp_path / "env"))
exe = os.path.realpath(
os.path.join(bin_dir, "{}{}".format(virtualenv.EXPECTED_EXE, ".exe" if virtualenv.IS_WIN else ""))
)
assert out == [
"startup",
"extend parser with count",
"adjust options",
"after install env with options 4",
"exe at {}".format(exe),
]
except subprocess.CalledProcessError as exception:
assert not exception.returncode, exception.output

View File

@ -1,44 +1,69 @@
import sys
from __future__ import absolute_import, unicode_literals
import os
import subprocess
import virtualenv
import sys
import pytest
VIRTUALENV_SCRIPT = virtualenv.__file__
import virtualenv
def test_commandline_basic(tmpdir):
"""Simple command line usage should work"""
subprocess.check_call([
sys.executable,
VIRTUALENV_SCRIPT,
str(tmpdir.join('venv'))
])
"""Simple command line usage should work and files should be generated"""
home_dir, lib_dir, inc_dir, bin_dir = virtualenv.path_locations(str(tmpdir.join("venv")))
subprocess.check_call([sys.executable, "-m", "virtualenv", "-vvv", home_dir, "--no-download"])
assert os.path.exists(home_dir)
assert os.path.exists(bin_dir)
assert os.path.exists(os.path.join(bin_dir, "activate"))
assert os.path.exists(os.path.join(bin_dir, "activate_this.py"))
assert os.path.exists(os.path.join(bin_dir, "activate.ps1"))
exe = os.path.join(bin_dir, os.path.basename(sys.executable))
assert os.path.exists(exe)
def _check_no_warnings(module):
subprocess.check_call((exe, "-Werror", "-c", "import {}".format(module)))
_check_no_warnings("distutils")
def test_commandline_os_path_sep(tmp_path):
path = tmp_path / "bad{}0".format(os.pathsep)
assert not path.exists()
process = subprocess.Popen(
[sys.executable, "-m", "virtualenv", str(path)],
cwd=str(tmp_path),
universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
)
out, err = process.communicate()
assert process.returncode == 3
msg = (
"ERROR: target path contains the operating system path separator '{}'\n"
"This is not allowed as would make the activation scripts unusable.\n".format(os.pathsep)
)
assert not err
assert out == msg
assert not path.exists()
def test_commandline_explicit_interp(tmpdir):
"""Specifying the Python interpreter should work"""
subprocess.check_call([
sys.executable,
VIRTUALENV_SCRIPT,
'-p', sys.executable,
str(tmpdir.join('venv'))
])
subprocess.check_call([sys.executable, "-m", "virtualenv", "-p", sys.executable, str(tmpdir.join("venv"))])
# The registry lookups to support the abbreviated "-p 3.5" form of specifying
# a Python interpreter on Windows don't seem to work with Python 3.5. The
# registry layout is not well documented, and it's not clear that the feature
# is sufficiently widely used to be worth fixing.
# See https://github.com/pypa/virtualenv/issues/864
@pytest.mark.skipif("sys.platform == 'win32' and sys.version_info[:2] >= (3,5)")
@pytest.mark.skipif("sys.platform == 'win32' and sys.version_info[:1] >= (3,)")
def test_commandline_abbrev_interp(tmpdir):
"""Specifying abbreviated forms of the Python interpreter should work"""
if sys.platform == 'win32':
fmt = '%s.%s'
else:
fmt = 'python%s.%s'
abbrev = fmt % (sys.version_info[0], sys.version_info[1])
subprocess.check_call([
sys.executable,
VIRTUALENV_SCRIPT,
'-p', abbrev,
str(tmpdir.join('venv'))
])
abbrev = "{}{}.{}".format("" if sys.platform == "win32" else "python", *sys.version_info[0:2])
subprocess.check_call([sys.executable, "-m", "virtualenv", "-p", abbrev, str(tmpdir.join("venv"))])

View File

@ -0,0 +1,49 @@
"""test using the project from source/package rather than install"""
from __future__ import absolute_import, unicode_literals
import os
import pytest
import virtualenv
try:
from pathlib import Path
except ImportError:
from pathlib2 import Path
ROOT_DIR = Path(__file__).parents[1]
def test_use_from_source_tree(tmp_path, clean_python, monkeypatch, call_subprocess):
"""test that we can create a virtual environment by feeding to a clean python the wheels content"""
monkeypatch.chdir(tmp_path)
call_subprocess(
[
str(Path(clean_python[1]) / virtualenv.EXPECTED_EXE),
str(Path(ROOT_DIR) / "virtualenv.py"),
"--no-download",
"env",
]
)
@pytest.mark.skipif(os.environ.get("TOX_PACKAGE") is None, reason="needs tox provisioned sdist")
def test_use_from_source_sdist(sdist, tmp_path, clean_python, monkeypatch, call_subprocess):
"""test that we can create a virtual environment by feeding to a clean python the sdist content"""
virtualenv_file = sdist / "virtualenv.py"
assert virtualenv_file.exists()
monkeypatch.chdir(tmp_path)
call_subprocess(
[str(Path(clean_python[1]) / virtualenv.EXPECTED_EXE), str(virtualenv_file), "--no-download", "env"]
)
def test_use_from_wheel(tmp_path, extracted_wheel, clean_python, monkeypatch, call_subprocess):
"""test that we can create a virtual environment by feeding to a clean python the wheels content"""
virtualenv_file = extracted_wheel / "virtualenv.py"
monkeypatch.chdir(tmp_path)
call_subprocess(
[str(Path(clean_python[1]) / virtualenv.EXPECTED_EXE), str(virtualenv_file), "--no-download", "env"]
)

View File

@ -0,0 +1,62 @@
import os
import pytest
import virtualenv
@pytest.mark.skipif(os.environ.get("TOX_PACKAGE") is None, reason="needs tox provisioned sdist")
def test_sdist_contains(sdist):
"""make assertions on what we package"""
content = set(sdist.iterdir())
names = {i.name for i in content}
must_have = {
# sources
"virtualenv.py",
"virtualenv_embedded",
"virtualenv_support",
"setup.py",
"setup.cfg",
"MANIFEST.in",
"pyproject.toml",
# test files
"tests",
# documentation
"docs",
"README.rst",
# helpers
"tasks",
"tox.ini",
# meta-data
"AUTHORS.txt",
"LICENSE.txt",
}
missing = must_have - names
assert not missing
extra = names - must_have - {"PKG-INFO", "virtualenv.egg-info"}
assert not extra, " | ".join(extra)
def test_wheel_contains(extracted_wheel):
content = set(extracted_wheel.iterdir())
names = {i.name for i in content}
must_have = {
# sources
"virtualenv.py",
"virtualenv_support",
"virtualenv-{}.dist-info".format(virtualenv.__version__),
}
assert must_have == names
support = {i.name for i in (extracted_wheel / "virtualenv_support").iterdir()}
assert "__init__.py" in support
for package in ("pip", "wheel", "setuptools"):
assert any(package in i for i in support)
meta = {i.name for i in (extracted_wheel / "virtualenv-{}.dist-info".format(virtualenv.__version__)).iterdir()}
assert {"entry_points.txt", "WHEEL", "RECORD", "METADATA", "top_level.txt", "zip-safe", "LICENSE.txt"} == meta

View File

@ -1,13 +1,34 @@
import virtualenv
from __future__ import absolute_import, unicode_literals
import inspect
import optparse
import os
import shutil
import subprocess
import sys
import tempfile
import pytest
import platform # noqa
import textwrap
import zipfile
from mock import patch, Mock
import pypiserver
import pytest
import pytest_localserver.http
import six
import virtualenv
try:
from pathlib import Path
from unittest.mock import NonCallableMock, call, patch
except ImportError:
from mock import NonCallableMock, call, patch
from pathlib2 import Path
try:
import venv as std_venv
except ImportError:
std_venv = None
def test_version():
@ -15,11 +36,222 @@ def test_version():
assert virtualenv.virtualenv_version, "Should have version"
@patch('os.path.exists')
def test_resolve_interpreter_with_absolute_path(mock_exists):
class TestGetInstalledPythons:
key_local_machine = "key-local-machine"
key_current_user = "key-current-user"
key_local_machine_64 = "key-local-machine-64"
key_current_user_64 = "key-current-user-64"
@classmethod
def mock_virtualenv_winreg(cls, monkeypatch, data):
def enum_key(key, index):
try:
return data.get(key, [])[index]
except IndexError:
raise WindowsError
def query_value(key, path):
installed_version_tags = data.get(key, [])
suffix = "\\InstallPath"
if path.endswith(suffix):
version_tag = path[: -len(suffix)]
if version_tag in installed_version_tags:
return "{}-{}-path".format(key, version_tag)
raise WindowsError
mock_winreg = NonCallableMock(
spec_set=[
"HKEY_LOCAL_MACHINE",
"HKEY_CURRENT_USER",
"KEY_READ",
"KEY_WOW64_32KEY",
"KEY_WOW64_64KEY",
"OpenKey",
"EnumKey",
"QueryValue",
"CloseKey",
]
)
mock_winreg.HKEY_LOCAL_MACHINE = "HKEY_LOCAL_MACHINE"
mock_winreg.HKEY_CURRENT_USER = "HKEY_CURRENT_USER"
mock_winreg.KEY_READ = 0x10
mock_winreg.KEY_WOW64_32KEY = 0x1
mock_winreg.KEY_WOW64_64KEY = 0x2
mock_winreg.OpenKey.side_effect = [
cls.key_local_machine,
cls.key_current_user,
cls.key_local_machine_64,
cls.key_current_user_64,
]
mock_winreg.EnumKey.side_effect = enum_key
mock_winreg.QueryValue.side_effect = query_value
mock_winreg.CloseKey.return_value = None
monkeypatch.setattr(virtualenv, "winreg", mock_winreg)
return mock_winreg
@pytest.mark.skipif(sys.platform == "win32", reason="non-windows specific test")
def test_on_non_windows(self, monkeypatch):
assert not virtualenv.IS_WIN
assert not hasattr(virtualenv, "winreg")
assert virtualenv.get_installed_pythons() == {}
@pytest.mark.skipif(sys.platform != "win32", reason="windows specific test")
def test_on_windows(self, monkeypatch):
assert virtualenv.IS_WIN
mock_winreg = self.mock_virtualenv_winreg(
monkeypatch,
{
self.key_local_machine: (
"2.4",
"2.7",
"3.2",
"3.4",
"3.6-32", # 32-bit only
"3.7-32", # both 32 & 64-bit with a 64-bit user install
),
self.key_current_user: ("2.5", "2.7", "3.8-32"),
self.key_local_machine_64: (
"2.6",
"3.5", # 64-bit only
"3.7",
"3.8", # 64-bit with a 32-bit user install
),
self.key_current_user_64: ("3.7",),
},
)
monkeypatch.setattr(virtualenv, "join", "{}\\{}".format)
installed_pythons = virtualenv.get_installed_pythons()
assert installed_pythons == {
"2": self.key_current_user + "-2.7-path\\python.exe",
"2-32": self.key_current_user + "-2.7-path\\python.exe",
"2-64": self.key_local_machine_64 + "-2.6-path\\python.exe",
"2.4": self.key_local_machine + "-2.4-path\\python.exe",
"2.4-32": self.key_local_machine + "-2.4-path\\python.exe",
"2.5": self.key_current_user + "-2.5-path\\python.exe",
"2.5-32": self.key_current_user + "-2.5-path\\python.exe",
"2.6": self.key_local_machine_64 + "-2.6-path\\python.exe",
"2.6-64": self.key_local_machine_64 + "-2.6-path\\python.exe",
"2.7": self.key_current_user + "-2.7-path\\python.exe",
"2.7-32": self.key_current_user + "-2.7-path\\python.exe",
"3": self.key_local_machine_64 + "-3.8-path\\python.exe",
"3-32": self.key_current_user + "-3.8-32-path\\python.exe",
"3-64": self.key_local_machine_64 + "-3.8-path\\python.exe",
"3.2": self.key_local_machine + "-3.2-path\\python.exe",
"3.2-32": self.key_local_machine + "-3.2-path\\python.exe",
"3.4": self.key_local_machine + "-3.4-path\\python.exe",
"3.4-32": self.key_local_machine + "-3.4-path\\python.exe",
"3.5": self.key_local_machine_64 + "-3.5-path\\python.exe",
"3.5-64": self.key_local_machine_64 + "-3.5-path\\python.exe",
"3.6": self.key_local_machine + "-3.6-32-path\\python.exe",
"3.6-32": self.key_local_machine + "-3.6-32-path\\python.exe",
"3.7": self.key_current_user_64 + "-3.7-path\\python.exe",
"3.7-32": self.key_local_machine + "-3.7-32-path\\python.exe",
"3.7-64": self.key_current_user_64 + "-3.7-path\\python.exe",
"3.8": self.key_local_machine_64 + "-3.8-path\\python.exe",
"3.8-32": self.key_current_user + "-3.8-32-path\\python.exe",
"3.8-64": self.key_local_machine_64 + "-3.8-path\\python.exe",
}
assert mock_winreg.mock_calls == [
call.OpenKey(mock_winreg.HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore", 0, 0x11),
call.EnumKey(self.key_local_machine, 0),
call.QueryValue(self.key_local_machine, "2.4\\InstallPath"),
call.EnumKey(self.key_local_machine, 1),
call.QueryValue(self.key_local_machine, "2.7\\InstallPath"),
call.EnumKey(self.key_local_machine, 2),
call.QueryValue(self.key_local_machine, "3.2\\InstallPath"),
call.EnumKey(self.key_local_machine, 3),
call.QueryValue(self.key_local_machine, "3.4\\InstallPath"),
call.EnumKey(self.key_local_machine, 4),
call.QueryValue(self.key_local_machine, "3.6-32\\InstallPath"),
call.EnumKey(self.key_local_machine, 5),
call.QueryValue(self.key_local_machine, "3.7-32\\InstallPath"),
call.EnumKey(self.key_local_machine, 6),
call.CloseKey(self.key_local_machine),
call.OpenKey(mock_winreg.HKEY_CURRENT_USER, "Software\\Python\\PythonCore", 0, 0x11),
call.EnumKey(self.key_current_user, 0),
call.QueryValue(self.key_current_user, "2.5\\InstallPath"),
call.EnumKey(self.key_current_user, 1),
call.QueryValue(self.key_current_user, "2.7\\InstallPath"),
call.EnumKey(self.key_current_user, 2),
call.QueryValue(self.key_current_user, "3.8-32\\InstallPath"),
call.EnumKey(self.key_current_user, 3),
call.CloseKey(self.key_current_user),
call.OpenKey(mock_winreg.HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore", 0, 0x12),
call.EnumKey(self.key_local_machine_64, 0),
call.QueryValue(self.key_local_machine_64, "2.6\\InstallPath"),
call.EnumKey(self.key_local_machine_64, 1),
call.QueryValue(self.key_local_machine_64, "3.5\\InstallPath"),
call.EnumKey(self.key_local_machine_64, 2),
call.QueryValue(self.key_local_machine_64, "3.7\\InstallPath"),
call.EnumKey(self.key_local_machine_64, 3),
call.QueryValue(self.key_local_machine_64, "3.8\\InstallPath"),
call.EnumKey(self.key_local_machine_64, 4),
call.CloseKey(self.key_local_machine_64),
call.OpenKey(mock_winreg.HKEY_CURRENT_USER, "Software\\Python\\PythonCore", 0, 0x12),
call.EnumKey(self.key_current_user_64, 0),
call.QueryValue(self.key_current_user_64, "3.7\\InstallPath"),
call.EnumKey(self.key_current_user_64, 1),
call.CloseKey(self.key_current_user_64),
]
@pytest.mark.skipif(sys.platform != "win32", reason="windows specific test")
def test_on_windows_with_no_installations(self, monkeypatch):
assert virtualenv.IS_WIN
mock_winreg = self.mock_virtualenv_winreg(monkeypatch, {})
installed_pythons = virtualenv.get_installed_pythons()
assert installed_pythons == {}
assert mock_winreg.mock_calls == [
call.OpenKey(mock_winreg.HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore", 0, 0x11),
call.EnumKey(self.key_local_machine, 0),
call.CloseKey(self.key_local_machine),
call.OpenKey(mock_winreg.HKEY_CURRENT_USER, "Software\\Python\\PythonCore", 0, 0x11),
call.EnumKey(self.key_current_user, 0),
call.CloseKey(self.key_current_user),
call.OpenKey(mock_winreg.HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore", 0, 0x12),
call.EnumKey(self.key_local_machine_64, 0),
call.CloseKey(self.key_local_machine_64),
call.OpenKey(mock_winreg.HKEY_CURRENT_USER, "Software\\Python\\PythonCore", 0, 0x12),
call.EnumKey(self.key_current_user_64, 0),
call.CloseKey(self.key_current_user_64),
]
@patch("distutils.spawn.find_executable")
@patch("virtualenv.is_executable", return_value=True)
@patch("virtualenv.get_installed_pythons")
@patch("os.path.exists", return_value=True)
@patch("os.path.abspath")
def test_resolve_interpreter_with_installed_python(
mock_abspath, mock_exists, mock_get_installed_pythons, mock_is_executable, mock_find_executable
):
test_tag = "foo"
test_path = "/path/to/foo/python.exe"
test_abs_path = "some-abs-path"
test_found_path = "some-found-path"
mock_get_installed_pythons.return_value = {test_tag: test_path, test_tag + "2": test_path + "2"}
mock_abspath.return_value = test_abs_path
mock_find_executable.return_value = test_found_path
exe = virtualenv.resolve_interpreter("foo")
assert exe == test_found_path, "installed python should be accessible by key"
mock_get_installed_pythons.assert_called_once_with()
mock_abspath.assert_called_once_with(test_path)
mock_find_executable.assert_called_once_with(test_path)
mock_exists.assert_called_once_with(test_found_path)
mock_is_executable.assert_called_once_with(test_found_path)
@patch("virtualenv.is_executable", return_value=True)
@patch("virtualenv.get_installed_pythons", return_value={"foo": "bar"})
@patch("os.path.exists", return_value=True)
def test_resolve_interpreter_with_absolute_path(mock_exists, mock_get_installed_pythons, mock_is_executable):
"""Should return absolute path if given and exists"""
mock_exists.return_value = True
virtualenv.is_executable = Mock(return_value=True)
test_abs_path = os.path.abspath("/usr/bin/python53")
exe = virtualenv.resolve_interpreter(test_abs_path)
@ -27,99 +259,99 @@ def test_resolve_interpreter_with_absolute_path(mock_exists):
assert exe == test_abs_path, "Absolute path should return as is"
mock_exists.assert_called_with(test_abs_path)
virtualenv.is_executable.assert_called_with(test_abs_path)
mock_is_executable.assert_called_with(test_abs_path)
@patch('os.path.exists')
def test_resolve_interpreter_with_nonexistent_interpreter(mock_exists):
@patch("virtualenv.get_installed_pythons", return_value={"foo": "bar"})
@patch("os.path.exists", return_value=False)
def test_resolve_interpreter_with_nonexistent_interpreter(mock_exists, mock_get_installed_pythons):
"""Should SystemExit with an nonexistent python interpreter path"""
mock_exists.return_value = False
with pytest.raises(SystemExit):
virtualenv.resolve_interpreter("/usr/bin/python53")
mock_exists.assert_called_with("/usr/bin/python53")
@patch('os.path.exists')
def test_resolve_interpreter_with_invalid_interpreter(mock_exists):
@patch("virtualenv.is_executable", return_value=False)
@patch("os.path.exists", return_value=True)
def test_resolve_interpreter_with_invalid_interpreter(mock_exists, mock_is_executable):
"""Should exit when with absolute path if not exists"""
mock_exists.return_value = True
virtualenv.is_executable = Mock(return_value=False)
invalid = os.path.abspath("/usr/bin/pyt_hon53")
with pytest.raises(SystemExit):
virtualenv.resolve_interpreter(invalid)
mock_exists.assert_called_with(invalid)
virtualenv.is_executable.assert_called_with(invalid)
mock_is_executable.assert_called_with(invalid)
def test_activate_after_future_statements():
"""Should insert activation line after last future statement"""
script = [
'#!/usr/bin/env python',
'from __future__ import with_statement',
'from __future__ import print_function',
'print("Hello, world!")'
]
assert virtualenv.relative_script(script) == [
'#!/usr/bin/env python',
'from __future__ import with_statement',
'from __future__ import print_function',
'',
"import os; activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); exec(compile(open(activate_this).read(), activate_this, 'exec'), dict(__file__=activate_this)); del os, activate_this",
'',
'print("Hello, world!")'
"#!/usr/bin/env python",
"from __future__ import with_statement",
"from __future__ import print_function",
'print("Hello, world!")',
]
out = virtualenv.relative_script(script)
assert out == [
"#!/usr/bin/env python",
"from __future__ import with_statement",
"from __future__ import print_function",
"",
"import os; "
"activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); "
"exec(compile(open(activate_this).read(), activate_this, 'exec'), { '__file__': activate_this}); "
"del os, activate_this",
"",
'print("Hello, world!")',
], out
def test_cop_update_defaults_with_store_false():
"""store_false options need reverted logic"""
class MyConfigOptionParser(virtualenv.ConfigOptionParser):
def __init__(self, *args, **kwargs):
self.config = virtualenv.ConfigParser.RawConfigParser()
self.files = []
optparse.OptionParser.__init__(self, *args, **kwargs)
def get_environ_vars(self, prefix='VIRTUALENV_'):
def get_environ_vars(self, prefix="VIRTUALENV_"):
yield ("no_site_packages", "1")
cop = MyConfigOptionParser()
cop.add_option(
'--no-site-packages',
dest='system_site_packages',
action='store_false',
help="Don't give access to the global site-packages dir to the "
"virtual environment (default)")
"--no-site-packages",
dest="system_site_packages",
action="store_false",
help="Don't give access to the global site-packages dir to the " "virtual environment (default)",
)
defaults = {}
cop.update_defaults(defaults)
assert defaults == {'system_site_packages': 0}
assert defaults == {"system_site_packages": 0}
def test_install_python_bin():
"""Should create the right python executables and links"""
tmp_virtualenv = tempfile.mkdtemp()
try:
home_dir, lib_dir, inc_dir, bin_dir = \
virtualenv.path_locations(tmp_virtualenv)
virtualenv.install_python(home_dir, lib_dir, inc_dir, bin_dir, False,
False)
home_dir, lib_dir, inc_dir, bin_dir = virtualenv.path_locations(tmp_virtualenv)
virtualenv.install_python(home_dir, lib_dir, inc_dir, bin_dir, False, False)
if virtualenv.is_win:
required_executables = ['python.exe', 'pythonw.exe']
if virtualenv.IS_WIN:
required_executables = ["python.exe", "pythonw.exe"]
else:
py_exe_no_version = 'python'
py_exe_version_major = 'python%s' % sys.version_info[0]
py_exe_version_major_minor = 'python%s.%s' % (
sys.version_info[0], sys.version_info[1])
required_executables = [py_exe_no_version, py_exe_version_major,
py_exe_version_major_minor]
py_exe_no_version = "python"
py_exe_version_major = "python%s" % sys.version_info[0]
py_exe_version_major_minor = "python{}.{}".format(sys.version_info[0], sys.version_info[1])
required_executables = [py_exe_no_version, py_exe_version_major, py_exe_version_major_minor]
for pth in required_executables:
assert os.path.exists(os.path.join(bin_dir, pth)), \
("%s should exist in bin_dir" % pth)
assert os.path.exists(os.path.join(bin_dir, pth)), "%s should exist in bin_dir" % pth
root_inc_dir = os.path.join(home_dir, "include")
assert not os.path.islink(root_inc_dir)
finally:
shutil.rmtree(tmp_virtualenv)
@ -128,14 +360,309 @@ def test_install_python_bin():
def test_always_copy_option():
"""Should be no symlinks in directory tree"""
tmp_virtualenv = tempfile.mkdtemp()
ve_path = os.path.join(tmp_virtualenv, 'venv')
ve_path = os.path.join(tmp_virtualenv, "venv")
try:
virtualenv.create_environment(ve_path, symlink=False)
for root, dirs, files in os.walk(tmp_virtualenv):
for f in files + dirs:
full_name = os.path.join(root, f)
assert not os.path.islink(full_name), "%s should not be a" \
" symlink (to %s)" % (full_name, os.readlink(full_name))
assert not os.path.islink(full_name), "%s should not be a" " symlink (to %s)" % (
full_name,
os.readlink(full_name),
)
finally:
shutil.rmtree(tmp_virtualenv)
@pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires working symlink implementation")
def test_relative_symlink(tmpdir):
""" Test if a virtualenv works correctly if it was created via a symlink and this symlink is removed """
tmpdir = str(tmpdir)
ve_path = os.path.join(tmpdir, "venv")
os.mkdir(ve_path)
workdir = os.path.join(tmpdir, "work")
os.mkdir(workdir)
ve_path_linked = os.path.join(workdir, "venv")
os.symlink(ve_path, ve_path_linked)
lib64 = os.path.join(ve_path, "lib64")
virtualenv.create_environment(ve_path_linked, symlink=True)
if not os.path.lexists(lib64):
# no lib 64 on this platform
return
assert os.path.exists(lib64)
shutil.rmtree(workdir)
assert os.path.exists(lib64)
@pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires working symlink implementation")
def test_copyfile_from_symlink(tmp_path):
"""Test that copyfile works correctly when the source is a symlink with a
relative target, and a symlink to a symlink. (This can occur when creating
an environment if Python was installed using stow or homebrew.)"""
# Set up src/link2 -> ../src/link1 -> file.
# We will copy to a different directory, so misinterpreting either symlink
# will be detected.
src_dir = tmp_path / "src"
src_dir.mkdir()
with open(str(src_dir / "file"), "w") as f:
f.write("contents")
os.symlink("file", str(src_dir / "link1"))
os.symlink(str(Path("..") / "src" / "link1"), str(src_dir / "link2"))
# Check that copyfile works on link2.
# This may produce a symlink or a regular file depending on the platform --
# which doesn't matter as long as it has the right contents.
copy_path = tmp_path / "copy"
virtualenv.copyfile(str(src_dir / "link2"), str(copy_path))
with open(str(copy_path), "r") as f:
assert f.read() == "contents"
shutil.rmtree(str(src_dir))
os.remove(str(copy_path))
def test_missing_certifi_pem(tmp_path):
"""Make sure that we can still create virtual environment if pip is
patched to not use certifi's cacert.pem and the file is removed.
This can happen if pip is packaged by Linux distributions."""
proj_dir = Path(__file__).parent.parent
support_original = proj_dir / "virtualenv_support"
pip_wheel = sorted(support_original.glob("pip*whl"))[0]
whl_name = pip_wheel.name
wheeldir = tmp_path / "wheels"
wheeldir.mkdir()
tmpcert = tmp_path / "tmpcert.pem"
cacert = "pip/_vendor/certifi/cacert.pem"
certifi = "pip/_vendor/certifi/core.py"
oldpath = b"os.path.join(f, 'cacert.pem')"
newpath = "r'{}'".format(tmpcert).encode()
removed = False
replaced = False
with zipfile.ZipFile(str(pip_wheel), "r") as whlin:
with zipfile.ZipFile(str(wheeldir / whl_name), "w") as whlout:
for item in whlin.infolist():
buff = whlin.read(item.filename)
if item.filename == cacert:
tmpcert.write_bytes(buff)
removed = True
continue
if item.filename == certifi:
nbuff = buff.replace(oldpath, newpath)
assert nbuff != buff
buff = nbuff
replaced = True
whlout.writestr(item, buff)
assert removed and replaced
venvdir = tmp_path / "venv"
search_dirs = [str(wheeldir), str(support_original)]
virtualenv.create_environment(str(venvdir), search_dirs=search_dirs)
def test_create_environment_from_dir_with_spaces(tmpdir):
"""Should work with wheel sources read from a dir with spaces."""
ve_path = str(tmpdir / "venv")
spaced_support_dir = str(tmpdir / "support with spaces")
from virtualenv_support import __file__ as support_dir
support_dir = os.path.dirname(os.path.abspath(support_dir))
shutil.copytree(support_dir, spaced_support_dir)
virtualenv.create_environment(ve_path, search_dirs=[spaced_support_dir])
def test_create_environment_in_dir_with_spaces(tmpdir):
"""Should work with environment path containing spaces."""
ve_path = str(tmpdir / "venv with spaces")
virtualenv.create_environment(ve_path)
def test_create_environment_with_local_https_pypi(tmpdir):
"""Create virtual environment using local PyPI listening https with
certificate signed with custom certificate authority
"""
test_dir = Path(__file__).parent
ssl_dir = test_dir / "ssl"
proj_dir = test_dir.parent
support_dir = proj_dir / "virtualenv_support"
local_pypi_app = pypiserver.app(root=str(support_dir))
local_pypi = pytest_localserver.http.WSGIServer(
host="localhost",
port=0,
application=local_pypi_app,
ssl_context=(str(ssl_dir / "server.crt"), str(ssl_dir / "server.key")),
)
local_pypi.start()
local_pypi_url = "https://localhost:{}/".format(local_pypi.server_address[1])
venvdir = tmpdir / "venv"
pip_log = tmpdir / "pip.log"
env_addition = {
"PIP_CERT": str(ssl_dir / "rootCA.pem"),
"PIP_INDEX_URL": local_pypi_url,
"PIP_LOG": str(pip_log),
"PIP_RETRIES": "0",
}
if six.PY2:
env_addition = {key.encode("utf-8"): value.encode("utf-8") for key, value in env_addition.items()}
env_backup = {}
for key, value in env_addition.items():
if key in os.environ:
env_backup[key] = os.environ[key]
os.environ[key] = value
try:
virtualenv.create_environment(str(venvdir), download=True)
with pip_log.open("rb") as f:
assert b"SSLError" not in f.read()
finally:
local_pypi.stop()
for key in env_addition.keys():
os.environ.pop(key)
if key in env_backup:
os.environ[key] = env_backup[key]
def check_pypy_pre_import():
import sys
# These modules(module_name, optional) are taken from PyPy's site.py:
# https://bitbucket.org/pypy/pypy/src/d0187cf2f1b70ec4b60f10673ff081bdd91e9a17/lib-python/2.7/site.py#lines-532:539
modules = [
("encodings", False),
("exceptions", True), # "exceptions" module does not exist in Python3
("zipimport", True),
]
for module, optional in modules:
if not optional or module in sys.builtin_module_names:
assert module in sys.modules, "missing {!r} in sys.modules".format(module)
@pytest.mark.skipif("platform.python_implementation() != 'PyPy'")
def test_pypy_pre_import(tmp_path):
"""For PyPy, some built-in modules should be pre-imported because
some programs expect them to be in sys.modules on startup.
"""
check_code = inspect.getsource(check_pypy_pre_import)
check_code = textwrap.dedent(check_code[check_code.index("\n") + 1 :])
if six.PY2:
check_code = check_code.decode()
check_prog = tmp_path / "check-pre-import.py"
check_prog.write_text(check_code)
ve_path = str(tmp_path / "venv")
virtualenv.create_environment(ve_path)
bin_dir = virtualenv.path_locations(ve_path)[-1]
try:
cmd = [
os.path.join(bin_dir, "{}{}".format(virtualenv.EXPECTED_EXE, ".exe" if virtualenv.IS_WIN else "")),
str(check_prog),
]
subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as exception:
assert not exception.returncode, exception.output
@pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires working symlink implementation")
def test_create_environment_with_exec_prefix_pointing_to_prefix(tmpdir):
"""Create virtual environment for Python with ``sys.exec_prefix`` pointing
to ``sys.prefix`` or ``sys.base_prefix`` or ``sys.real_prefix`` under a
different name
"""
venvdir = str(tmpdir / "venv")
python_dir = tmpdir / "python"
python_dir.mkdir()
path_key = str("PATH")
old_path = os.environ[path_key]
if hasattr(sys, "real_prefix"):
os.environ[path_key] = os.pathsep.join(
p for p in os.environ[path_key].split(os.pathsep) if not p.startswith(sys.prefix)
)
python = virtualenv.resolve_interpreter(os.path.basename(sys.executable))
try:
subprocess.check_call([sys.executable, "-m", "virtualenv", "-p", python, venvdir])
home_dir, lib_dir, inc_dir, bin_dir = virtualenv.path_locations(venvdir)
assert not os.path.islink(os.path.join(lib_dir, "distutils"))
finally:
os.environ[path_key] = old_path
@pytest.mark.skipif(not hasattr(sys, "real_prefix"), reason="requires running from inside virtualenv")
def test_create_environment_from_virtual_environment(tmpdir):
"""Create virtual environment using Python from another virtual environment
"""
venvdir = str(tmpdir / "venv")
home_dir, lib_dir, inc_dir, bin_dir = virtualenv.path_locations(venvdir)
virtualenv.create_environment(venvdir)
assert not os.path.islink(os.path.join(lib_dir, "distutils"))
@pytest.mark.skipif(std_venv is None, reason="needs standard venv module")
def test_create_environment_from_venv(tmpdir):
std_venv_dir = str(tmpdir / "stdvenv")
ve_venv_dir = str(tmpdir / "vevenv")
home_dir, lib_dir, inc_dir, bin_dir = virtualenv.path_locations(ve_venv_dir)
builder = std_venv.EnvBuilder()
ctx = builder.ensure_directories(std_venv_dir)
builder.create_configuration(ctx)
builder.setup_python(ctx)
builder.setup_scripts(ctx)
subprocess.check_call([ctx.env_exe, virtualenv.__file__, "--no-setuptools", "--no-pip", "--no-wheel", ve_venv_dir])
ve_exe = os.path.join(bin_dir, "python")
out = subprocess.check_output([ve_exe, "-c", "import sys; print(sys.real_prefix)"], universal_newlines=True)
# Test against real_prefix if present - we might be running the test from a virtualenv (e.g. tox).
assert out.strip() == getattr(sys, "real_prefix", sys.prefix)
@pytest.mark.skipif(std_venv is None, reason="needs standard venv module")
def test_create_environment_from_venv_no_pip(tmpdir):
std_venv_dir = str(tmpdir / "stdvenv")
ve_venv_dir = str(tmpdir / "vevenv")
home_dir, lib_dir, inc_dir, bin_dir = virtualenv.path_locations(ve_venv_dir)
builder = std_venv.EnvBuilder()
ctx = builder.ensure_directories(std_venv_dir)
builder.create_configuration(ctx)
builder.setup_python(ctx)
builder.setup_scripts(ctx)
subprocess.check_call([ctx.env_exe, virtualenv.__file__, "--no-pip", ve_venv_dir])
ve_exe = os.path.join(bin_dir, "python")
out = subprocess.check_output([ve_exe, "-c", "import sys; print(sys.real_prefix)"], universal_newlines=True)
# Test against real_prefix if present - we might be running the test from a virtualenv (e.g. tox).
assert out.strip() == getattr(sys, "real_prefix", sys.prefix)
def test_create_environment_with_old_pip(tmpdir):
old = Path(__file__).parent / "old-wheels"
old_pip = old / "pip-9.0.1-py2.py3-none-any.whl"
old_setuptools = old / "setuptools-30.4.0-py2.py3-none-any.whl"
support_dir = str(tmpdir / "virtualenv_support")
os.makedirs(support_dir)
for old_dep in [old_pip, old_setuptools]:
shutil.copy(str(old_dep), support_dir)
venvdir = str(tmpdir / "venv")
virtualenv.create_environment(venvdir, search_dirs=[support_dir], no_wheel=True)
def test_license_builtin(clean_python):
_, bin_dir, _ = clean_python
proc = subprocess.Popen(
(os.path.join(bin_dir, "python"), "-c", "license()"), stdin=subprocess.PIPE, stdout=subprocess.PIPE
)
out_b, _ = proc.communicate(b"q\n")
out = out_b.decode()
assert not proc.returncode
assert "Ian Bicking and Contributors" not in out

View File

@ -0,0 +1,100 @@
from __future__ import unicode_literals
import json
import os.path
import subprocess
import sys
import pytest
import six
import virtualenv
HERE = os.path.dirname(os.path.dirname(__file__))
def _python(v):
return virtualenv.get_installed_pythons().get(v, "python{}".format(v))
@pytest.fixture(scope="session")
def call_zipapp(tmp_path_factory, call_subprocess):
if sys.version_info < (3, 5):
pytest.skip("zipapp was introduced in python3.5")
pyz = str(tmp_path_factory.mktemp(basename="zipapp") / "virtualenv.pyz")
call_subprocess(
(sys.executable, os.path.join(HERE, "tasks/make_zipapp.py"), "--root", virtualenv.HERE, "--dest", pyz)
)
def zipapp_make_env(path, python=None):
cmd = (sys.executable, pyz, "--no-download", path)
if python:
cmd += ("-p", python)
call_subprocess(cmd)
return zipapp_make_env
@pytest.fixture(scope="session")
def call_wheel(tmp_path_factory, call_subprocess):
wheels = tmp_path_factory.mktemp(basename="wheel")
call_subprocess((sys.executable, "-m", "pip", "wheel", "--no-deps", "-w", str(wheels), HERE))
(wheel,) = wheels.iterdir()
def wheel_make_env(path, python=None):
cmd = (sys.executable, "-m", "virtualenv", "--no-download", path)
if python:
cmd += ("-p", python)
env = dict(os.environ, PYTHONPATH=str(wheel))
call_subprocess(cmd, env=env)
return wheel_make_env
def test_zipapp_basic_invocation(call_zipapp, tmp_path):
_test_basic_invocation(call_zipapp, tmp_path)
def test_wheel_basic_invocation(call_wheel, tmp_path):
_test_basic_invocation(call_wheel, tmp_path)
def _test_basic_invocation(make_env, tmp_path):
venv = tmp_path / "venv"
make_env(str(venv))
assert_venv_looks_good(
venv, list(sys.version_info), "{}{}".format(virtualenv.EXPECTED_EXE, ".exe" if virtualenv.IS_WIN else "")
)
def version_exe(venv, exe_name):
_, _, _, bin_dir = virtualenv.path_locations(str(venv))
exe = os.path.join(bin_dir, exe_name)
script = "import sys; import json; print(json.dumps(dict(v=list(sys.version_info), e=sys.executable)))"
cmd = [exe, "-c", script]
out = json.loads(subprocess.check_output(cmd, universal_newlines=True))
return out["v"], out["e"]
def assert_venv_looks_good(venv, version_info, exe_name):
assert venv.exists()
version, exe = version_exe(venv, exe_name=exe_name)
assert version[: len(version_info)] == version_info
assert exe != sys.executable
def _test_invocation_dash_p(make_env, tmp_path):
venv = tmp_path / "venv"
python = {2: _python("3"), 3: _python("2.7")}[sys.version_info[0]]
make_env(str(venv), python)
expected = {3: 2, 2: 3}[sys.version_info[0]]
assert_venv_looks_good(venv, [expected], "python{}".format(".exe" if virtualenv.IS_WIN else ""))
def test_zipapp_invocation_dash_p(call_zipapp, tmp_path):
_test_invocation_dash_p(call_zipapp, tmp_path)
@pytest.mark.skipif(sys.platform == "win32" and six.PY2, reason="no python 3 for windows on CI")
def test_wheel_invocation_dash_p(call_wheel, tmp_path):
_test_invocation_dash_p(call_wheel, tmp_path)

127
python/virtualenv/tox.ini Normal file
View File

@ -0,0 +1,127 @@
[tox]
minversion = 3.6.1
envlist = fix_lint, embed, py{27,34,35,36,37}, pypy{,3}, cross_python{2,3}, docs, package_readme
isolated_build = true
skip_missing_interpreters = true
[testenv]
description = run tests with {basepython}
deps = pip >= 19.1.1
setenv = COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}/.coverage.{envname}}
passenv = https_proxy http_proxy no_proxy HOME PYTEST_* PIP_* CI_RUN TERM
extras = testing
install_command = python -m pip install {opts} {packages} --disable-pip-version-check
commands = coverage run --source=virtualenv \
-m pytest tests \
{posargs:\
--junitxml={env:JUNIT_XML_FILE:{toxworkdir}/junit.{envname}.xml} \
}
coverage combine
coverage report --show-missing
[testenv:coverage]
description = [run locally after tests]: combine coverage data and create report;
generates a diff coverage against origin/master (can be changed by setting DIFF_AGAINST env var)
deps = {[testenv]deps}
coverage >= 4.4.1, < 5
diff_cover
extras =
skip_install = True
passenv = DIFF_AGAINST
setenv = COVERAGE_FILE={toxworkdir}/.coverage
commands = coverage combine
coverage report --show-missing
coverage xml -o {toxworkdir}/coverage.xml
coverage html -d {toxworkdir}/htmlcov
diff-cover --compare-branch {env:DIFF_AGAINST:origin/master} {toxworkdir}/coverage.xml
[testenv:cross_python2]
description = test creating a python3 venv with a python2-based virtualenv
basepython = python2
extras =
commands = virtualenv -p python3 {envtmpdir}/{envname}
{envtmpdir}/{envname}/bin/python -V 2>&1 | grep "Python 3"
[testenv:cross_python3]
description = test creating a python2 venv with a python3-based virtualenv
basepython = python3
extras =
commands = virtualenv -p python2 {envtmpdir}/{envname}
{envtmpdir}/{envname}/bin/python -V 2>&1 | grep "Python 2"
[testenv:docs]
basepython = python3
description = build documentation
extras = docs
commands = sphinx-build -d "{envtmpdir}/doctree" -W docs "{toxworkdir}/docs_out" --color -bhtml {posargs}
python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))'
[testenv:package_readme]
description = check that the long description is valid (need for PyPi)
deps = {[testenv]deps}
twine >= 1.12.1
skip_install = true
extras =
commands = pip wheel -w {envtmpdir}/build --no-deps .
twine check {envtmpdir}/build/*
[testenv:embed]
description = embed dependencies into virtualenv.py
skip_install = true
changedir = {toxinidir}/tasks
extras =
commands = python update_embedded.py
[testenv:upgrade]
description = upgrade pip/wheels/setuptools to latest
skip_install = true
changedir = {toxinidir}/tasks
commands = python upgrade_wheels.py
[testenv:fix_lint]
description = format the code base to adhere to our styles, and complain about what we cannot do automatically
basepython = python3.8
passenv = *
deps = {[testenv]deps}
pre-commit >= 1.12.0, <2
skip_install = True
commands = pre-commit run --all-files --show-diff-on-failure
python -c 'import pathlib; print("hint: run \{\} install to add checks as pre-commit hook".format(pathlib.Path(r"{envdir}") / "bin" / "pre-commit"))'
[isort]
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
line_length = 120
known_standard_library = ConfigParser
known_first_party = virtualenv
known_third_party = git,packaging,pypiserver,pytest,pytest_localserver,setuptools,six
[flake8]
max-complexity = 22
max-line-length = 120
ignore = E203, W503, C901, E402
exclude = virtualenv_embedded/site.py
[pep8]
max-line-length = 120
[testenv:dev]
description = generate a DEV environment
extras = testing, docs
usedevelop = True
commands = python -m pip list --format=columns
python -c 'import sys; print(sys.executable)'
[testenv:release]
description = do a release, required posarg of the version number
basepython = python3.8
skip_install = true
passenv = *
deps = {[testenv]deps}
gitpython >= 2.1.10, < 3
towncrier >= 18.5.0
packaging >= 17.1
changedir = {toxinidir}/tasks
commands = python release.py --version {posargs}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
@echo off
set "VIRTUAL_ENV=__VIRTUAL_ENV__"
if defined _OLD_VIRTUAL_PROMPT (
@ -7,9 +8,13 @@ if defined _OLD_VIRTUAL_PROMPT (
if not defined PROMPT (
set "PROMPT=$P$G"
)
set "_OLD_VIRTUAL_PROMPT=%PROMPT%"
if not defined VIRTUAL_ENV_DISABLE_PROMPT (
set "_OLD_VIRTUAL_PROMPT=%PROMPT%"
)
)
if not defined VIRTUAL_ENV_DISABLE_PROMPT (
set "PROMPT=__VIRTUAL_WINPROMPT__%PROMPT%"
)
set "PROMPT=__VIRTUAL_WINPROMPT__ %PROMPT%"
REM Don't use () to avoid problems with them in %PATH%
if defined _OLD_VIRTUAL_PYTHONHOME goto ENDIFVHOME

View File

@ -2,35 +2,54 @@
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc'
set newline='\
'
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH:q" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT:q" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc'
# Unset irrelevant variables.
deactivate nondestructive
setenv VIRTUAL_ENV "__VIRTUAL_ENV__"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/__BIN_NAME__:$PATH"
set _OLD_VIRTUAL_PATH="$PATH:q"
setenv PATH "$VIRTUAL_ENV:q/__BIN_NAME__:$PATH:q"
if ("__VIRTUAL_PROMPT__" != "") then
set env_name = "__VIRTUAL_PROMPT__"
else
set env_name = `basename "$VIRTUAL_ENV"`
set env_name = '('"$VIRTUAL_ENV:t:q"') '
endif
# Could be in a non-interactive environment,
# in which case, $prompt is undefined and we wouldn't
# care about the prompt anyway.
if ( $?prompt ) then
set _OLD_VIRTUAL_PROMPT="$prompt"
set prompt = "[$env_name] $prompt"
if ( $?VIRTUAL_ENV_DISABLE_PROMPT ) then
if ( $VIRTUAL_ENV_DISABLE_PROMPT == "" ) then
set do_prompt = "1"
else
set do_prompt = "0"
endif
else
set do_prompt = "1"
endif
if ( $do_prompt == "1" ) then
# Could be in a non-interactive environment,
# in which case, $prompt is undefined and we wouldn't
# care about the prompt anyway.
if ( $?prompt ) then
set _OLD_VIRTUAL_PROMPT="$prompt:q"
if ( "$prompt:q" =~ *"$newline:q"* ) then
:
else
set prompt = "$env_name:q$prompt:q"
endif
endif
endif
unset env_name
unset do_prompt
alias pydoc python -m pydoc
rehash

View File

@ -1,10 +1,28 @@
# This file must be used using `. bin/activate.fish` *within a running fish ( http://fishshell.com ) session*.
# This file must be used using `source bin/activate.fish` *within a running fish ( http://fishshell.com ) session*.
# Do not run it directly.
function _bashify_path -d "Converts a fish path to something bash can recognize"
set fishy_path $argv
set bashy_path $fishy_path[1]
for path_part in $fishy_path[2..-1]
set bashy_path "$bashy_path:$path_part"
end
echo $bashy_path
end
function _fishify_path -d "Converts a bash path to something fish can recognize"
echo $argv | tr ':' '\n'
end
function deactivate -d 'Exit virtualenv mode and return to the normal environment.'
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
# https://github.com/fish-shell/fish-shell/issues/436 altered PATH handling
if test (echo $FISH_VERSION | tr "." "\n")[1] -lt 3
set -gx PATH (_fishify_path $_OLD_VIRTUAL_PATH)
else
set -gx PATH $_OLD_VIRTUAL_PATH
end
set -e _OLD_VIRTUAL_PATH
end
@ -14,6 +32,7 @@ function deactivate -d 'Exit virtualenv mode and return to the normal environmen
end
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
and functions -q _old_fish_prompt
# Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`.
set -l fish_function_path
@ -30,6 +49,8 @@ function deactivate -d 'Exit virtualenv mode and return to the normal environmen
# Self-destruct!
functions -e pydoc
functions -e deactivate
functions -e _bashify_path
functions -e _fishify_path
end
end
@ -38,7 +59,12 @@ deactivate nondestructive
set -gx VIRTUAL_ENV "__VIRTUAL_ENV__"
set -gx _OLD_VIRTUAL_PATH $PATH
# https://github.com/fish-shell/fish-shell/issues/436 altered PATH handling
if test (echo $FISH_VERSION | tr "." "\n")[1] -lt 3
set -gx _OLD_VIRTUAL_PATH (_bashify_path $PATH)
else
set -gx _OLD_VIRTUAL_PATH $PATH
end
set -gx PATH "$VIRTUAL_ENV/__BIN_NAME__" $PATH
# Unset `$PYTHONHOME` if set.

View File

@ -1,150 +1,60 @@
# This file must be dot sourced from PoSh; you cannot run it
# directly. Do this: . ./activate.ps1
# FIXME: clean up unused vars.
$script:THIS_PATH = $myinvocation.mycommand.path
$script:BASE_DIR = split-path (resolve-path "$THIS_PATH/..") -Parent
$script:DIR_NAME = split-path $BASE_DIR -Leaf
$script:BASE_DIR = Split-Path (Resolve-Path "$THIS_PATH/..") -Parent
function global:deactivate ( [switch] $NonDestructive ){
if ( test-path variable:_OLD_VIRTUAL_PATH ) {
function global:deactivate([switch] $NonDestructive) {
if (Test-Path variable:_OLD_VIRTUAL_PATH) {
$env:PATH = $variable:_OLD_VIRTUAL_PATH
remove-variable "_OLD_VIRTUAL_PATH" -scope global
Remove-Variable "_OLD_VIRTUAL_PATH" -Scope global
}
if ( test-path function:_old_virtual_prompt ) {
if (Test-Path function:_old_virtual_prompt) {
$function:prompt = $function:_old_virtual_prompt
remove-item function:\_old_virtual_prompt
Remove-Item function:\_old_virtual_prompt
}
if ($env:VIRTUAL_ENV) {
$old_env = split-path $env:VIRTUAL_ENV -leaf
remove-item env:VIRTUAL_ENV -erroraction silentlycontinue
Remove-Item env:VIRTUAL_ENV -ErrorAction SilentlyContinue
}
if ( !$NonDestructive ) {
if (!$NonDestructive) {
# Self destruct!
remove-item function:deactivate
Remove-Item function:deactivate
Remove-Item function:pydoc
}
}
function global:pydoc {
python -m pydoc $args
}
# unset irrelevant variables
deactivate -nondestructive
$VIRTUAL_ENV = $BASE_DIR
$env:VIRTUAL_ENV = $VIRTUAL_ENV
$global:_OLD_VIRTUAL_PATH = $env:PATH
$env:PATH = "$env:VIRTUAL_ENV/Scripts;" + $env:PATH
if (! $env:VIRTUAL_ENV_DISABLE_PROMPT) {
function global:_old_virtual_prompt { "" }
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
$env:PATH = "$env:VIRTUAL_ENV/__BIN_NAME____PATH_SEP__" + $env:PATH
if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
function global:_old_virtual_prompt {
""
}
$function:_old_virtual_prompt = $function:prompt
function global:prompt {
# Add a prefix to the current prompt, but don't discard it.
write-host "($(split-path $env:VIRTUAL_ENV -leaf)) " -nonewline
& $function:_old_virtual_prompt
if ("__VIRTUAL_PROMPT__" -ne "") {
function global:prompt {
# Add the custom prefix to the existing prompt
$previous_prompt_value = & $function:_old_virtual_prompt
("__VIRTUAL_PROMPT__" + $previous_prompt_value)
}
}
else {
function global:prompt {
# Add a prefix to the current prompt, but don't discard it.
$previous_prompt_value = & $function:_old_virtual_prompt
$new_prompt_value = "($( Split-Path $env:VIRTUAL_ENV -Leaf )) "
($new_prompt_value + $previous_prompt_value)
}
}
}
# SIG # Begin signature block
# MIISeAYJKoZIhvcNAQcCoIISaTCCEmUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUS5reBwSg3zOUwhXf2jPChZzf
# yPmggg6tMIIGcDCCBFigAwIBAgIBJDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQG
# EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp
# Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy
# dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjIwMTQ2WhcNMTcxMDI0MjIw
# MTQ2WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp
# BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV
# BAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgT2JqZWN0
# IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyiOLIjUemqAbPJ1J
# 0D8MlzgWKbr4fYlbRVjvhHDtfhFN6RQxq0PjTQxRgWzwFQNKJCdU5ftKoM5N4YSj
# Id6ZNavcSa6/McVnhDAQm+8H3HWoD030NVOxbjgD/Ih3HaV3/z9159nnvyxQEckR
# ZfpJB2Kfk6aHqW3JnSvRe+XVZSufDVCe/vtxGSEwKCaNrsLc9pboUoYIC3oyzWoU
# TZ65+c0H4paR8c8eK/mC914mBo6N0dQ512/bkSdaeY9YaQpGtW/h/W/FkbQRT3sC
# pttLVlIjnkuY4r9+zvqhToPjxcfDYEf+XD8VGkAqle8Aa8hQ+M1qGdQjAye8OzbV
# uUOw7wIDAQABo4IB6TCCAeUwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
# AQYwHQYDVR0OBBYEFNBOD0CZbLhLGW87KLjg44gHNKq3MB8GA1UdIwQYMBaAFE4L
# 7xqkQFulF2mHMMo0aEPQQa7yMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAoYh
# aHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3J0MFsGA1UdHwRUMFIwJ6Al
# oCOGIWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDAnoCWgI4YhaHR0
# cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMIGABgNVHSAEeTB3MHUGCysG
# AQQBgbU3AQIBMGYwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29t
# L3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t
# L2ludGVybWVkaWF0ZS5wZGYwEQYJYIZIAYb4QgEBBAQDAgABMFAGCWCGSAGG+EIB
# DQRDFkFTdGFydENvbSBDbGFzcyAyIFByaW1hcnkgSW50ZXJtZWRpYXRlIE9iamVj
# dCBTaWduaW5nIENlcnRpZmljYXRlczANBgkqhkiG9w0BAQUFAAOCAgEAcnMLA3Va
# N4OIE9l4QT5OEtZy5PByBit3oHiqQpgVEQo7DHRsjXD5H/IyTivpMikaaeRxIv95
# baRd4hoUcMwDj4JIjC3WA9FoNFV31SMljEZa66G8RQECdMSSufgfDYu1XQ+cUKxh
# D3EtLGGcFGjjML7EQv2Iol741rEsycXwIXcryxeiMbU2TPi7X3elbwQMc4JFlJ4B
# y9FhBzuZB1DV2sN2irGVbC3G/1+S2doPDjL1CaElwRa/T0qkq2vvPxUgryAoCppU
# FKViw5yoGYC+z1GaesWWiP1eFKAL0wI7IgSvLzU3y1Vp7vsYaxOVBqZtebFTWRHt
# XjCsFrrQBngt0d33QbQRI5mwgzEp7XJ9xu5d6RVWM4TPRUsd+DDZpBHm9mszvi9g
# VFb2ZG7qRRXCSqys4+u/NLBPbXi/m/lU00cODQTlC/euwjk9HQtRrXQ/zqsBJS6U
# J+eLGw1qOfj+HVBl/ZQpfoLk7IoWlRQvRL1s7oirEaqPZUIWY/grXq9r6jDKAp3L
# ZdKQpPOnnogtqlU4f7/kLjEJhrrc98mrOWmVMK/BuFRAfQ5oDUMnVmCzAzLMjKfG
# cVW/iMew41yfhgKbwpfzm3LBr1Zv+pEBgcgW6onRLSAn3XHM0eNtz+AkxH6rRf6B
# 2mYhLEEGLapH8R1AMAo4BbVFOZR5kXcMCwowggg1MIIHHaADAgECAgIEuDANBgkq
# hkiG9w0BAQUFADCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0
# ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcx
# ODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUg
# T2JqZWN0IENBMB4XDTExMTIwMzE1MzQxOVoXDTEzMTIwMzE0NTgwN1owgYwxIDAe
# BgNVBA0TFzU4MTc5Ni1HaDd4Zkp4a3hRU0lPNEUwMQswCQYDVQQGEwJERTEPMA0G
# A1UECBMGQmVybGluMQ8wDQYDVQQHEwZCZXJsaW4xFjAUBgNVBAMTDUphbm5pcyBM
# ZWlkZWwxITAfBgkqhkiG9w0BCQEWEmphbm5pc0BsZWlkZWwuaW5mbzCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMcPeABYdN7nPq/AkZ/EkyUBGx/l2Yui
# Lfm8ZdLG0ulMb/kQL3fRY7sUjYPyn9S6PhqqlFnNoGHJvbbReCdUC9SIQYmOEjEA
# raHfb7MZU10NjO4U2DdGucj2zuO5tYxKizizOJF0e4yRQZVxpUGdvkW/+GLjCNK5
# L7mIv3Z1dagxDKHYZT74HXiS4VFUwHF1k36CwfM2vsetdm46bdgSwV+BCMmZICYT
# IJAS9UQHD7kP4rik3bFWjUx08NtYYFAVOd/HwBnemUmJe4j3IhZHr0k1+eDG8hDH
# KVvPgLJIoEjC4iMFk5GWsg5z2ngk0LLu3JZMtckHsnnmBPHQK8a3opUNd8hdMNJx
# gOwKjQt2JZSGUdIEFCKVDqj0FmdnDMPfwy+FNRtpBMl1sz78dUFhSrnM0D8NXrqa
# 4rG+2FoOXlmm1rb6AFtpjAKksHRpYcPk2DPGWp/1sWB+dUQkS3gOmwFzyqeTuXpT
# 0juqd3iAxOGx1VRFQ1VHLLf3AzV4wljBau26I+tu7iXxesVucSdsdQu293jwc2kN
# xK2JyHCoZH+RyytrwS0qw8t7rMOukU9gwP8mn3X6mgWlVUODMcHTULjSiCEtvyZ/
# aafcwjUbt4ReEcnmuZtWIha86MTCX7U7e+cnpWG4sIHPnvVTaz9rm8RyBkIxtFCB
# nQ3FnoQgyxeJAgMBAAGjggOdMIIDmTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIH
# gDAuBgNVHSUBAf8EJDAiBggrBgEFBQcDAwYKKwYBBAGCNwIBFQYKKwYBBAGCNwoD
# DTAdBgNVHQ4EFgQUWyCgrIWo8Ifvvm1/YTQIeMU9nc8wHwYDVR0jBBgwFoAU0E4P
# QJlsuEsZbzsouODjiAc0qrcwggIhBgNVHSAEggIYMIICFDCCAhAGCysGAQQBgbU3
# AQICMIIB/zAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9s
# aWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50
# ZXJtZWRpYXRlLnBkZjCB9wYIKwYBBQUHAgIwgeowJxYgU3RhcnRDb20gQ2VydGlm
# aWNhdGlvbiBBdXRob3JpdHkwAwIBARqBvlRoaXMgY2VydGlmaWNhdGUgd2FzIGlz
# c3VlZCBhY2NvcmRpbmcgdG8gdGhlIENsYXNzIDIgVmFsaWRhdGlvbiByZXF1aXJl
# bWVudHMgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeSwgcmVsaWFuY2Ugb25seSBm
# b3IgdGhlIGludGVuZGVkIHB1cnBvc2UgaW4gY29tcGxpYW5jZSBvZiB0aGUgcmVs
# eWluZyBwYXJ0eSBvYmxpZ2F0aW9ucy4wgZwGCCsGAQUFBwICMIGPMCcWIFN0YXJ0
# Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MAMCAQIaZExpYWJpbGl0eSBhbmQg
# d2FycmFudGllcyBhcmUgbGltaXRlZCEgU2VlIHNlY3Rpb24gIkxlZ2FsIGFuZCBM
# aW1pdGF0aW9ucyIgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeS4wNgYDVR0fBC8w
# LTAroCmgJ4YlaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0YzItY3JsLmNybDCB
# iQYIKwYBBQUHAQEEfTB7MDcGCCsGAQUFBzABhitodHRwOi8vb2NzcC5zdGFydHNz
# bC5jb20vc3ViL2NsYXNzMi9jb2RlL2NhMEAGCCsGAQUFBzAChjRodHRwOi8vYWlh
# LnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xhc3MyLmNvZGUuY2EuY3J0MCMGA1Ud
# EgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzANBgkqhkiG9w0BAQUFAAOC
# AQEAhrzEV6zwoEtKjnFRhCsjwiPykVpo5Eiye77Ve801rQDiRKgSCCiW6g3HqedL
# OtaSs65Sj2pm3Viea4KR0TECLcbCTgsdaHqw2x1yXwWBQWZEaV6EB05lIwfr94P1
# SFpV43zkuc+bbmA3+CRK45LOcCNH5Tqq7VGTCAK5iM7tvHwFlbQRl+I6VEL2mjpF
# NsuRjDOVrv/9qw/a22YJ9R7Y1D0vUSs3IqZx2KMUaYDP7H2mSRxJO2nADQZBtriF
# gTyfD3lYV12MlIi5CQwe3QC6DrrfSMP33i5Wa/OFJiQ27WPxmScYVhiqozpImFT4
# PU9goiBv9RKXdgTmZE1PN0NQ5jGCAzUwggMxAgEBMIGTMIGMMQswCQYDVQQGEwJJ
# TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
# YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
# MiBQcmltYXJ5IEludGVybWVkaWF0ZSBPYmplY3QgQ0ECAgS4MAkGBSsOAwIaBQCg
# eDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE
# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJ
# BDEWBBRVGw0FDSiaIi38dWteRUAg/9Pr6DANBgkqhkiG9w0BAQEFAASCAgCInvOZ
# FdaNFzbf6trmFDZKMojyx3UjKMCqNjHVBbuKY0qXwFC/ElYDV1ShJ2CBZbdurydO
# OQ6cIQ0KREOCwmX/xB49IlLHHUxNhEkVv7HGU3EKAFf9IBt9Yr7jikiR9cjIsfHK
# 4cjkoKJL7g28yEpLLkHt1eo37f1Ga9lDWEa5Zq3U5yX+IwXhrUBm1h8Xr033FhTR
# VEpuSz6LHtbrL/zgJnCzJ2ahjtJoYevdcWiNXffosJHFaSfYDDbiNsPRDH/1avmb
# 5j/7BhP8BcBaR6Fp8tFbNGIcWHHGcjqLMnTc4w13b7b4pDhypqElBa4+lCmwdvv9
# GydYtRgPz8GHeoBoKj30YBlMzRIfFYaIFGIC4Ai3UEXkuH9TxYohVbGm/W0Kl4Lb
# RJ1FwiVcLcTOJdgNId2vQvKc+jtNrjcg5SP9h2v/C4aTx8tyc6tE3TOPh2f9b8DL
# S+SbVArJpuJqrPTxDDoO1QNjTgLcdVYeZDE+r/NjaGZ6cMSd8db3EaG3ijD/0bud
# SItbm/OlNVbQOFRR76D+ZNgPcU5iNZ3bmvQQIg6aSB9MHUpIE/SeCkNl9YeVk1/1
# GFULgNMRmIYP4KLvu9ylh5Gu3hvD5VNhH6+FlXANwFy07uXks5uF8mfZVxVCnodG
# xkNCx+6PsrA5Z7WP4pXcmYnMn97npP/Q9EHJWw==
# SIG # End signature block

View File

@ -1,12 +1,18 @@
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly
if [ "${BASH_SOURCE-}" = "$0" ]; then
echo "You must source this script: \$ source $0" >&2
exit 33
fi
deactivate () {
unset -f pydoc >/dev/null 2>&1
# reset old environment variables
# ! [ -z ${VAR+_} ] returns true if VAR is declared at all
if ! [ -z "${_OLD_VIRTUAL_PATH+_}" ] ; then
if ! [ -z "${_OLD_VIRTUAL_PATH:+_}" ] ; then
PATH="$_OLD_VIRTUAL_PATH"
export PATH
unset _OLD_VIRTUAL_PATH
@ -54,17 +60,17 @@ if ! [ -z "${PYTHONHOME+_}" ] ; then
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then
_OLD_VIRTUAL_PS1="$PS1"
_OLD_VIRTUAL_PS1="${PS1-}"
if [ "x__VIRTUAL_PROMPT__" != x ] ; then
PS1="__VIRTUAL_PROMPT__$PS1"
PS1="__VIRTUAL_PROMPT__${PS1-}"
else
PS1="(`basename \"$VIRTUAL_ENV\"`) $PS1"
PS1="(`basename \"$VIRTUAL_ENV\"`) ${PS1-}"
fi
export PS1
fi
# Make sure to unalias pydoc if it's already there
alias pydoc 2>/dev/null >/dev/null && unalias pydoc
alias pydoc 2>/dev/null >/dev/null && unalias pydoc || true
pydoc () {
python -m pydoc "$@"

View File

@ -0,0 +1,46 @@
"""Xonsh activate script for virtualenv"""
from xonsh.tools import get_sep as _get_sep
def _deactivate(args):
if "pydoc" in aliases:
del aliases["pydoc"]
if ${...}.get("_OLD_VIRTUAL_PATH", ""):
$PATH = $_OLD_VIRTUAL_PATH
del $_OLD_VIRTUAL_PATH
if ${...}.get("_OLD_VIRTUAL_PYTHONHOME", ""):
$PYTHONHOME = $_OLD_VIRTUAL_PYTHONHOME
del $_OLD_VIRTUAL_PYTHONHOME
if "VIRTUAL_ENV" in ${...}:
del $VIRTUAL_ENV
if "VIRTUAL_ENV_PROMPT" in ${...}:
del $VIRTUAL_ENV_PROMPT
if "nondestructive" not in args:
# Self destruct!
del aliases["deactivate"]
# unset irrelevant variables
_deactivate(["nondestructive"])
aliases["deactivate"] = _deactivate
$VIRTUAL_ENV = r"__VIRTUAL_ENV__"
$_OLD_VIRTUAL_PATH = $PATH
$PATH = $PATH[:]
$PATH.add($VIRTUAL_ENV + _get_sep() + "__BIN_NAME__", front=True, replace=True)
if ${...}.get("PYTHONHOME", ""):
# unset PYTHONHOME if set
$_OLD_VIRTUAL_PYTHONHOME = $PYTHONHOME
del $PYTHONHOME
$VIRTUAL_ENV_PROMPT = "__VIRTUAL_PROMPT__"
if not $VIRTUAL_ENV_PROMPT:
del $VIRTUAL_ENV_PROMPT
aliases["pydoc"] = ["python", "-m", "pydoc"]

View File

@ -1,34 +1,46 @@
"""By using execfile(this_file, dict(__file__=this_file)) you will
activate this virtualenv environment.
"""Activate virtualenv for current interpreter:
This can be used when you must use an existing Python interpreter, not
the virtualenv bin/python
Use exec(open(this_file).read(), {'__file__': this_file}).
This can be used when you must use an existing Python interpreter, not the virtualenv bin/python.
"""
import os
import site
import sys
try:
__file__
except NameError:
raise AssertionError(
"You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))")
import sys
import os
raise AssertionError("You must use exec(open(this_file).read(), {'__file__': this_file}))")
old_os_path = os.environ.get('PATH', '')
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if sys.platform == 'win32':
site_packages = os.path.join(base, 'Lib', 'site-packages')
# prepend bin to PATH (this file is inside the bin directory)
bin_dir = os.path.dirname(os.path.abspath(__file__))
os.environ["PATH"] = os.pathsep.join([bin_dir] + os.environ.get("PATH", "").split(os.pathsep))
base = os.path.dirname(bin_dir)
# virtual env is right above bin directory
os.environ["VIRTUAL_ENV"] = base
# add the virtual environments site-package to the host python import mechanism
IS_PYPY = hasattr(sys, "pypy_version_info")
IS_JYTHON = sys.platform.startswith("java")
if IS_JYTHON:
site_packages = os.path.join(base, "Lib", "site-packages")
elif IS_PYPY:
site_packages = os.path.join(base, "site-packages")
else:
site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages')
prev_sys_path = list(sys.path)
import site
IS_WIN = sys.platform == "win32"
if IS_WIN:
site_packages = os.path.join(base, "Lib", "site-packages")
else:
site_packages = os.path.join(base, "lib", "python{}.{}".format(*sys.version_info), "site-packages")
prev = set(sys.path)
site.addsitedir(site_packages)
sys.real_prefix = sys.prefix
sys.prefix = base
# Move the added items to the front of the path:
new_sys_path = []
for item in list(sys.path):
if item not in prev_sys_path:
new_sys_path.append(item)
sys.path.remove(item)
sys.path[:0] = new_sys_path
# Move the added items to the front of the path, in place
new = list(sys.path)
sys.path[:] = [i for i in new if i not in prev] + [i for i in new if i in prev]

View File

@ -16,4 +16,4 @@ if not defined _OLD_VIRTUAL_PYTHONHOME goto ENDIFVHOME
if not defined _OLD_VIRTUAL_PATH goto ENDIFVPATH
set "PATH=%_OLD_VIRTUAL_PATH%"
set _OLD_VIRTUAL_PATH=
:ENDIFVPATH
:ENDIFVPATH

View File

@ -1,20 +1,39 @@
import os
import sys
import warnings
import imp
import opcode # opcode is not a virtualenv module, so we can use it to find the stdlib
# Important! To work on pypy, this must be a module that resides in the
# lib-python/modified-x.y.z directory
import warnings
# opcode is not a virtualenv module, so we can use it to find the stdlib
# Important! To work on pypy, this must be a module that resides in the
# lib-python/modified-x.y.z directory
import opcode
dirname = os.path.dirname
distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils')
distutils_path = os.path.join(os.path.dirname(opcode.__file__), "distutils")
if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)):
warnings.warn(
"The virtualenv distutils package at %s appears to be in the same location as the system distutils?")
warnings.warn("The virtualenv distutils package at %s appears to be in the same location as the system distutils?")
else:
__path__.insert(0, distutils_path)
real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ('', '', imp.PKG_DIRECTORY))
__path__.insert(0, distutils_path) # noqa: F821
if sys.version_info < (3, 4):
import imp
real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ("", "", imp.PKG_DIRECTORY))
else:
import importlib.machinery
distutils_path = os.path.join(distutils_path, "__init__.py")
loader = importlib.machinery.SourceFileLoader("_virtualenv_distutils", distutils_path)
if sys.version_info < (3, 5):
import types
real_distutils = types.ModuleType(loader.name)
else:
import importlib.util
spec = importlib.util.spec_from_loader(loader.name, loader)
real_distutils = importlib.util.module_from_spec(spec)
loader.exec_module(real_distutils)
# Copy the relevant attributes
try:
__revision__ = real_distutils.__revision__
@ -22,80 +41,94 @@ else:
pass
__version__ = real_distutils.__version__
from distutils import dist, sysconfig
from distutils import dist, sysconfig # isort:skip
try:
basestring
except NameError:
basestring = str
## patch build_ext (distutils doesn't know how to get the libs directory
## path on windows - it hardcodes the paths around the patched sys.prefix)
# patch build_ext (distutils doesn't know how to get the libs directory
# path on windows - it hardcodes the paths around the patched sys.prefix)
if sys.platform == 'win32':
if sys.platform == "win32":
from distutils.command.build_ext import build_ext as old_build_ext
class build_ext(old_build_ext):
def finalize_options (self):
def finalize_options(self):
if self.library_dirs is None:
self.library_dirs = []
elif isinstance(self.library_dirs, basestring):
self.library_dirs = self.library_dirs.split(os.pathsep)
self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs"))
old_build_ext.finalize_options(self)
from distutils.command import build_ext as build_ext_module
from distutils.command import build_ext as build_ext_module
build_ext_module.build_ext = build_ext
## distutils.dist patches:
# distutils.dist patches:
old_find_config_files = dist.Distribution.find_config_files
def find_config_files(self):
found = old_find_config_files(self)
system_distutils = os.path.join(distutils_path, 'distutils.cfg')
#if os.path.exists(system_distutils):
# found.insert(0, system_distutils)
# What to call the per-user config file
if os.name == 'posix':
if os.name == "posix":
user_filename = ".pydistutils.cfg"
else:
user_filename = "pydistutils.cfg"
user_filename = os.path.join(sys.prefix, user_filename)
if os.path.isfile(user_filename):
for item in list(found):
if item.endswith('pydistutils.cfg'):
if item.endswith("pydistutils.cfg"):
found.remove(item)
found.append(user_filename)
return found
dist.Distribution.find_config_files = find_config_files
## distutils.sysconfig patches:
# distutils.sysconfig patches:
old_get_python_inc = sysconfig.get_python_inc
def sysconfig_get_python_inc(plat_specific=0, prefix=None):
if prefix is None:
prefix = sys.real_prefix
return old_get_python_inc(plat_specific, prefix)
sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__
sysconfig.get_python_inc = sysconfig_get_python_inc
old_get_python_lib = sysconfig.get_python_lib
def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
if standard_lib and prefix is None:
prefix = sys.real_prefix
return old_get_python_lib(plat_specific, standard_lib, prefix)
sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__
sysconfig.get_python_lib = sysconfig_get_python_lib
old_get_config_vars = sysconfig.get_config_vars
def sysconfig_get_config_vars(*args):
real_vars = old_get_config_vars(*args)
if sys.platform == 'win32':
if sys.platform == "win32":
lib_dir = os.path.join(sys.real_prefix, "libs")
if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars:
real_vars['LIBDIR'] = lib_dir # asked for all
elif isinstance(real_vars, list) and 'LIBDIR' in args:
real_vars = real_vars + [lib_dir] # asked for list
if isinstance(real_vars, dict) and "LIBDIR" not in real_vars:
real_vars["LIBDIR"] = lib_dir # asked for all
elif isinstance(real_vars, list) and "LIBDIR" in args:
real_vars = real_vars + [lib_dir] # asked for list
return real_vars
sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__
sysconfig.get_config_vars = sysconfig_get_config_vars

View File

@ -63,8 +63,9 @@ ImportError exception, it is silently ignored.
"""
import sys
import os
import sys
try:
import __builtin__ as builtins
except ImportError:
@ -83,33 +84,25 @@ ENABLE_USER_SITE = None
USER_SITE = None
USER_BASE = None
_is_64bit = (getattr(sys, 'maxsize', None) or getattr(sys, 'maxint')) > 2**32
_is_pypy = hasattr(sys, 'pypy_version_info')
_is_jython = sys.platform[:4] == 'java'
if _is_jython:
ModuleType = type(os)
_is_64bit = (getattr(sys, "maxsize", None) or getattr(sys, "maxint")) > 2 ** 32
_is_pypy = hasattr(sys, "pypy_version_info")
def makepath(*paths):
dir = os.path.join(*paths)
if _is_jython and (dir == '__classpath__' or
dir.startswith('__pyclasspath__')):
return dir, dir
dir = os.path.abspath(dir)
return dir, os.path.normcase(dir)
def abs__file__():
"""Set all module' __file__ attribute to an absolute path"""
for m in sys.modules.values():
if ((_is_jython and not isinstance(m, ModuleType)) or
hasattr(m, '__loader__')):
# only modules need the abspath in Jython. and don't mess
# with a PEP 302-supplied __file__
continue
f = getattr(m, '__file__', None)
f = getattr(m, "__file__", None)
if f is None:
continue
m.__file__ = os.path.abspath(f)
def removeduppaths():
""" Remove duplicate entries from sys.path along with making them
absolute"""
@ -128,18 +121,21 @@ def removeduppaths():
sys.path[:] = L
return known_paths
# XXX This should not be part of site.py, since it is needed even when
# using the -S option for Python. See http://www.python.org/sf/586680
def addbuilddir():
"""Append ./build/lib.<platform> in case we're running in the build dir
(especially for Guido :-)"""
from distutils.util import get_platform
s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
if hasattr(sys, 'gettotalrefcount'):
s += '-pydebug'
s = "build/lib.{}-{}.{}".format(get_platform(), *sys.version_info)
if hasattr(sys, "gettotalrefcount"):
s += "-pydebug"
s = os.path.join(os.path.dirname(sys.path[-1]), s)
sys.path.append(s)
def _init_pathinfo():
"""Return a set containing all existing directory entries from sys.path"""
d = set()
@ -152,6 +148,7 @@ def _init_pathinfo():
continue
return d
def addpackage(sitedir, name, known_paths):
"""Add a new path to known_paths by combining sitedir and 'name' or execute
sitedir if it starts with 'import'"""
@ -162,7 +159,7 @@ def addpackage(sitedir, name, known_paths):
reset = 0
fullname = os.path.join(sitedir, name)
try:
f = open(fullname, "rU")
f = open(fullname, "r")
except IOError:
return
try:
@ -183,6 +180,7 @@ def addpackage(sitedir, name, known_paths):
known_paths = None
return known_paths
def addsitedir(sitedir, known_paths=None):
"""Add 'sitedir' argument to sys.path if missing and handle .pth files in
'sitedir'"""
@ -193,7 +191,7 @@ def addsitedir(sitedir, known_paths=None):
reset = 0
sitedir, sitedircase = makepath(sitedir)
if not sitedircase in known_paths:
sys.path.append(sitedir) # Add path component
sys.path.append(sitedir) # Add path component
try:
names = os.listdir(sitedir)
except os.error:
@ -206,6 +204,7 @@ def addsitedir(sitedir, known_paths=None):
known_paths = None
return known_paths
def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_prefix):
"""Add site-packages (and possibly site-python) to sys.path"""
prefixes = [os.path.join(sys_prefix, "local"), sys_prefix]
@ -214,31 +213,32 @@ def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_pre
for prefix in prefixes:
if prefix:
if sys.platform in ('os2emx', 'riscos') or _is_jython:
if sys.platform in ("os2emx", "riscos"):
sitedirs = [os.path.join(prefix, "Lib", "site-packages")]
elif _is_pypy:
sitedirs = [os.path.join(prefix, 'site-packages')]
elif sys.platform == 'darwin' and prefix == sys_prefix:
sitedirs = [os.path.join(prefix, "site-packages")]
elif sys.platform == "darwin" and prefix == sys_prefix:
if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python
if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python
sitedirs = [os.path.join("/Library/Python", sys.version[:3], "site-packages"),
os.path.join(prefix, "Extras", "lib", "python")]
sitedirs = [
os.path.join("/Library/Python", "{}.{}".format(*sys.version_info), "site-packages"),
os.path.join(prefix, "Extras", "lib", "python"),
]
else: # any other Python distros on OSX work this way
sitedirs = [os.path.join(prefix, "lib",
"python" + sys.version[:3], "site-packages")]
else: # any other Python distros on OSX work this way
sitedirs = [os.path.join(prefix, "lib", "python{}.{}".format(*sys.version_info), "site-packages")]
elif os.sep == '/':
sitedirs = [os.path.join(prefix,
"lib",
"python" + sys.version[:3],
"site-packages"),
os.path.join(prefix, "lib", "site-python"),
os.path.join(prefix, "python" + sys.version[:3], "lib-dynload")]
lib64_dir = os.path.join(prefix, "lib64", "python" + sys.version[:3], "site-packages")
if (os.path.exists(lib64_dir) and
os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]):
elif os.sep == "/":
sitedirs = [
os.path.join(prefix, "lib", "python{}.{}".format(*sys.version_info), "site-packages"),
os.path.join(prefix, "lib", "site-python"),
os.path.join(prefix, "python{}.{}".format(*sys.version_info), "lib-dynload"),
]
lib64_dir = os.path.join(prefix, "lib64", "python{}.{}".format(*sys.version_info), "site-packages")
if os.path.exists(lib64_dir) and os.path.realpath(lib64_dir) not in [
os.path.realpath(p) for p in sitedirs
]:
if _is_64bit:
sitedirs.insert(0, lib64_dir)
else:
@ -246,42 +246,40 @@ def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_pre
try:
# sys.getobjects only available in --with-pydebug build
sys.getobjects
sitedirs.insert(0, os.path.join(sitedirs[0], 'debug'))
sitedirs.insert(0, os.path.join(sitedirs[0], "debug"))
except AttributeError:
pass
# Debian-specific dist-packages directories:
sitedirs.append(os.path.join(prefix, "local/lib",
"python" + sys.version[:3],
"dist-packages"))
if sys.version[0] == '2':
sitedirs.append(os.path.join(prefix, "lib",
"python" + sys.version[:3],
"dist-packages"))
sitedirs.append(
os.path.join(prefix, "local/lib", "python{}.{}".format(*sys.version_info), "dist-packages")
)
if sys.version_info[0] == 2:
sitedirs.append(
os.path.join(prefix, "lib", "python{}.{}".format(*sys.version_info), "dist-packages")
)
else:
sitedirs.append(os.path.join(prefix, "lib",
"python" + sys.version[0],
"dist-packages"))
sitedirs.append(
os.path.join(prefix, "lib", "python{}".format(sys.version_info[0]), "dist-packages")
)
sitedirs.append(os.path.join(prefix, "lib", "dist-python"))
else:
sitedirs = [prefix, os.path.join(prefix, "lib", "site-packages")]
if sys.platform == 'darwin':
if sys.platform == "darwin":
# for framework builds *only* we add the standard Apple
# locations. Currently only per-user, but /Library and
# /Network/Library could be added too
if 'Python.framework' in prefix:
home = os.environ.get('HOME')
if "Python.framework" in prefix or "Python3.framework" in prefix:
home = os.environ.get("HOME")
if home:
sitedirs.append(
os.path.join(home,
'Library',
'Python',
sys.version[:3],
'site-packages'))
os.path.join(home, "Library", "Python", "{}.{}".format(*sys.version_info), "site-packages")
)
for sitedir in sitedirs:
if os.path.isdir(sitedir):
addsitedir(sitedir, known_paths)
return None
def check_enableusersite():
"""Check if user site directory is safe for inclusion
@ -292,7 +290,7 @@ def check_enableusersite():
False: Disabled by user (command line option)
True: Safe and enabled
"""
if hasattr(sys, 'flags') and getattr(sys.flags, 'no_user_site', False):
if hasattr(sys, "flags") and getattr(sys.flags, "no_user_site", False):
return False
if hasattr(os, "getuid") and hasattr(os, "geteuid"):
@ -306,6 +304,7 @@ def check_enableusersite():
return True
def addusersitepackages(known_paths):
"""Add a per user site-package to sys.path
@ -324,7 +323,7 @@ def addusersitepackages(known_paths):
def joinuser(*args):
return os.path.expanduser(os.path.join(*args))
#if sys.platform in ('os2emx', 'riscos'):
# if sys.platform in ('os2emx', 'riscos'):
# # Don't know what to put here
# USER_BASE = ''
# USER_SITE = ''
@ -334,31 +333,24 @@ def addusersitepackages(known_paths):
USER_BASE = env_base
else:
USER_BASE = joinuser(base, "Python")
USER_SITE = os.path.join(USER_BASE,
"Python" + sys.version[0] + sys.version[2],
"site-packages")
USER_SITE = os.path.join(USER_BASE, "Python{}{}".format(*sys.version_info), "site-packages")
else:
if env_base:
USER_BASE = env_base
else:
USER_BASE = joinuser("~", ".local")
USER_SITE = os.path.join(USER_BASE, "lib",
"python" + sys.version[:3],
"site-packages")
USER_SITE = os.path.join(USER_BASE, "lib", "python{}.{}".format(*sys.version_info), "site-packages")
if ENABLE_USER_SITE and os.path.isdir(USER_SITE):
addsitedir(USER_SITE, known_paths)
if ENABLE_USER_SITE:
for dist_libdir in ("lib", "local/lib"):
user_site = os.path.join(USER_BASE, dist_libdir,
"python" + sys.version[:3],
"dist-packages")
user_site = os.path.join(USER_BASE, dist_libdir, "python{}.{}".format(*sys.version_info), "dist-packages")
if os.path.isdir(user_site):
addsitedir(user_site, known_paths)
return known_paths
def setBEGINLIBPATH():
"""The OS/2 EMX port has optional extension modules that do double duty
as DLLs (and must use the .DLL file extension) for other extensions.
@ -368,12 +360,12 @@ def setBEGINLIBPATH():
"""
dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload")
libpath = os.environ['BEGINLIBPATH'].split(';')
libpath = os.environ["BEGINLIBPATH"].split(";")
if libpath[-1]:
libpath.append(dllpath)
else:
libpath[-1] = dllpath
os.environ['BEGINLIBPATH'] = ';'.join(libpath)
os.environ["BEGINLIBPATH"] = ";".join(libpath)
def setquit():
@ -381,18 +373,20 @@ def setquit():
These are simply strings that display a hint on how to exit.
"""
if os.sep == ':':
eof = 'Cmd-Q'
elif os.sep == '\\':
eof = 'Ctrl-Z plus Return'
if os.sep == ":":
eof = "Cmd-Q"
elif os.sep == "\\":
eof = "Ctrl-Z plus Return"
else:
eof = 'Ctrl-D (i.e. EOF)'
eof = "Ctrl-D (i.e. EOF)"
class Quitter(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Use %s() or %s to exit' % (self.name, eof)
return "Use {}() or {} to exit".format(self.name, eof)
def __call__(self, code=None):
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
@ -401,8 +395,9 @@ def setquit():
except:
pass
raise SystemExit(code)
builtins.quit = Quitter('quit')
builtins.exit = Quitter('exit')
builtins.quit = Quitter("quit")
builtins.exit = Quitter("exit")
class _Printer(object):
@ -426,7 +421,7 @@ class _Printer(object):
for filename in self.__files:
filename = os.path.join(dir, filename)
try:
fp = open(filename, "rU")
fp = open(filename, "r")
data = fp.read()
fp.close()
break
@ -436,7 +431,7 @@ class _Printer(object):
break
if not data:
data = self.__data
self.__lines = data.split('\n')
self.__lines = data.split("\n")
self.__linecnt = len(self.__lines)
def __repr__(self):
@ -444,11 +439,11 @@ class _Printer(object):
if len(self.__lines) <= self.MAXLINES:
return "\n".join(self.__lines)
else:
return "Type %s() to see the full %s text" % ((self.__name,)*2)
return "Type %s() to see the full %s text" % ((self.__name,) * 2)
def __call__(self):
self.__setup()
prompt = 'Hit Return for more, or q (and Return) to quit: '
prompt = "Hit Return for more, or q (and Return) to quit: "
lineno = 0
while 1:
try:
@ -464,31 +459,31 @@ class _Printer(object):
key = raw_input(prompt)
except NameError:
key = input(prompt)
if key not in ('', 'q'):
if key not in ("", "q"):
key = None
if key == 'q':
if key == "q":
break
def setcopyright():
"""Set 'copyright' and 'credits' in __builtin__"""
builtins.copyright = _Printer("copyright", sys.copyright)
if _is_jython:
builtins.credits = _Printer(
"credits",
"Jython is maintained by the Jython developers (www.jython.org).")
elif _is_pypy:
builtins.credits = _Printer(
"credits",
"PyPy is maintained by the PyPy developers: http://pypy.org/")
if _is_pypy:
builtins.credits = _Printer("credits", "PyPy is maintained by the PyPy developers: http://pypy.org/")
else:
builtins.credits = _Printer("credits", """\
builtins.credits = _Printer(
"credits",
"""\
Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
for supporting Python development. See www.python.org for more information.""")
for supporting Python development. See www.python.org for more information.""",
)
here = os.path.dirname(os.__file__)
builtins.license = _Printer(
"license", "See http://www.python.org/%.3s/license.html" % sys.version,
"license",
"See https://www.python.org/psf/license/",
["LICENSE.txt", "LICENSE"],
[os.path.join(here, os.pardir), here, os.curdir])
[sys.prefix, os.path.join(here, os.pardir), here, os.curdir],
)
class _Helper(object):
@ -498,38 +493,45 @@ class _Helper(object):
"""
def __repr__(self):
return "Type help() for interactive help, " \
"or help(object) for help about object."
return "Type help() for interactive help, " "or help(object) for help about object."
def __call__(self, *args, **kwds):
import pydoc
return pydoc.help(*args, **kwds)
def sethelper():
builtins.help = _Helper()
def aliasmbcs():
"""On Windows, some default encodings are not provided by Python,
while they are always available as "mbcs" in each locale. Make
them usable by aliasing to "mbcs" in such a case."""
if sys.platform == 'win32':
if sys.platform == "win32":
import locale, codecs
enc = locale.getdefaultlocale()[1]
if enc.startswith('cp'): # "cp***" ?
if enc.startswith("cp"): # "cp***" ?
try:
codecs.lookup(enc)
except LookupError:
import encodings
encodings._cache[enc] = encodings._unknown
encodings.aliases.aliases[enc] = 'mbcs'
encodings.aliases.aliases[enc] = "mbcs"
def setencoding():
"""Set the string encoding used by the Unicode implementation. The
default is 'ascii', but if you're willing to experiment, you can
change this."""
encoding = "ascii" # Default value set by _PyUnicode_Init()
encoding = "ascii" # Default value set by _PyUnicode_Init()
if 0:
# Enable to support locale aware default string encodings.
import locale
loc = locale.getdefaultlocale()
if loc[1]:
encoding = loc[1]
@ -539,7 +541,7 @@ def setencoding():
encoding = "undefined"
if encoding != "ascii":
# On Non-Unicode builds this will raise an AttributeError...
sys.setdefaultencoding(encoding) # Needs Python Unicode build !
sys.setdefaultencoding(encoding) # Needs Python Unicode build !
def execsitecustomize():
@ -549,41 +551,38 @@ def execsitecustomize():
except ImportError:
pass
def virtual_install_main_packages():
f = open(os.path.join(os.path.dirname(__file__), 'orig-prefix.txt'))
f = open(os.path.join(os.path.dirname(__file__), "orig-prefix.txt"))
sys.real_prefix = f.read().strip()
f.close()
pos = 2
hardcoded_relative_dirs = []
if sys.path[0] == '':
if sys.path[0] == "":
pos += 1
if _is_jython:
paths = [os.path.join(sys.real_prefix, 'Lib')]
elif _is_pypy:
if _is_pypy:
if sys.version_info > (3, 2):
cpyver = '%d' % sys.version_info[0]
cpyver = "%d" % sys.version_info[0]
elif sys.pypy_version_info >= (1, 5):
cpyver = '%d.%d' % sys.version_info[:2]
cpyver = "%d.%d" % sys.version_info[:2]
else:
cpyver = '%d.%d.%d' % sys.version_info[:3]
paths = [os.path.join(sys.real_prefix, 'lib_pypy'),
os.path.join(sys.real_prefix, 'lib-python', cpyver)]
cpyver = "%d.%d.%d" % sys.version_info[:3]
paths = [os.path.join(sys.real_prefix, "lib_pypy"), os.path.join(sys.real_prefix, "lib-python", cpyver)]
if sys.pypy_version_info < (1, 9):
paths.insert(1, os.path.join(sys.real_prefix,
'lib-python', 'modified-%s' % cpyver))
hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
paths.insert(1, os.path.join(sys.real_prefix, "lib-python", "modified-%s" % cpyver))
hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
#
# This is hardcoded in the Python executable, but relative to sys.prefix:
for path in paths[:]:
plat_path = os.path.join(path, 'plat-%s' % sys.platform)
plat_path = os.path.join(path, "plat-%s" % sys.platform)
if os.path.exists(plat_path):
paths.append(plat_path)
elif sys.platform == 'win32':
paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')]
elif sys.platform == "win32":
paths = [os.path.join(sys.real_prefix, "Lib"), os.path.join(sys.real_prefix, "DLLs")]
else:
paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3])]
hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python'+sys.version[:3])
paths = [os.path.join(sys.real_prefix, "lib", "python{}.{}".format(*sys.version_info))]
hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
lib64_path = os.path.join(sys.real_prefix, "lib64", "python{}.{}".format(*sys.version_info))
if os.path.exists(lib64_path):
if _is_64bit:
paths.insert(0, lib64_path)
@ -595,28 +594,28 @@ def virtual_install_main_packages():
# Python 3.3+, this lives in sys.implementation, while in Python 2.7
# it lives in sys.
try:
arch = getattr(sys, 'implementation', sys)._multiarch
arch = getattr(sys, "implementation", sys)._multiarch
except AttributeError:
# This is a non-multiarch aware Python. Fallback to the old way.
arch = sys.platform
plat_path = os.path.join(sys.real_prefix, 'lib',
'python'+sys.version[:3],
'plat-%s' % arch)
plat_path = os.path.join(sys.real_prefix, "lib", "python{}.{}".format(*sys.version_info), "plat-%s" % arch)
if os.path.exists(plat_path):
paths.append(plat_path)
# This is hardcoded in the Python executable, but
# relative to sys.prefix, so we have to fix up:
for path in list(paths):
tk_dir = os.path.join(path, 'lib-tk')
tk_dir = os.path.join(path, "lib-tk")
if os.path.exists(tk_dir):
paths.append(tk_dir)
# These are hardcoded in the Apple's Python executable,
# but relative to sys.prefix, so we have to fix them up:
if sys.platform == 'darwin':
hardcoded_paths = [os.path.join(relative_dir, module)
for relative_dir in hardcoded_relative_dirs
for module in ('plat-darwin', 'plat-mac', 'plat-mac/lib-scriptpackages')]
if sys.platform == "darwin":
hardcoded_paths = [
os.path.join(relative_dir, module)
for relative_dir in hardcoded_relative_dirs
for module in ("plat-darwin", "plat-mac", "plat-mac/lib-scriptpackages")
]
for path in hardcoded_paths:
if os.path.exists(path):
@ -624,6 +623,7 @@ def virtual_install_main_packages():
sys.path.extend(paths)
def force_global_eggs_after_local_site_packages():
"""
Force easy_installed eggs in the global environment to get placed
@ -633,29 +633,17 @@ def force_global_eggs_after_local_site_packages():
around.
"""
egginsert = getattr(sys, '__egginsert', 0)
egginsert = getattr(sys, "__egginsert", 0)
for i, path in enumerate(sys.path):
if i > egginsert and path.startswith(sys.prefix):
egginsert = i
sys.__egginsert = egginsert + 1
def virtual_addsitepackages(known_paths):
force_global_eggs_after_local_site_packages()
return addsitepackages(known_paths, sys_prefix=sys.real_prefix)
def fixclasspath():
"""Adjust the special classpath sys.path entries for Jython. These
entries should follow the base virtualenv lib directories.
"""
paths = []
classpaths = []
for path in sys.path:
if path == '__classpath__' or path.startswith('__pyclasspath__'):
classpaths.append(path)
else:
paths.append(path)
sys.path = paths
sys.path.extend(classpaths)
def execusercustomize():
"""Run custom user specific code, if available."""
@ -665,17 +653,92 @@ def execusercustomize():
pass
def enablerlcompleter():
"""Enable default readline configuration on interactive prompts, by
registering a sys.__interactivehook__.
If the readline module can be imported, the hook will set the Tab key
as completion key and register ~/.python_history as history file.
This can be overridden in the sitecustomize or usercustomize module,
or in a PYTHONSTARTUP file.
"""
def register_readline():
import atexit
try:
import readline
import rlcompleter
except ImportError:
return
# Reading the initialization (config) file may not be enough to set a
# completion key, so we set one first and then read the file.
readline_doc = getattr(readline, "__doc__", "")
if readline_doc is not None and "libedit" in readline_doc:
readline.parse_and_bind("bind ^I rl_complete")
else:
readline.parse_and_bind("tab: complete")
try:
readline.read_init_file()
except OSError:
# An OSError here could have many causes, but the most likely one
# is that there's no .inputrc file (or .editrc file in the case of
# Mac OS X + libedit) in the expected location. In that case, we
# want to ignore the exception.
pass
if readline.get_current_history_length() == 0:
# If no history was loaded, default to .python_history.
# The guard is necessary to avoid doubling history size at
# each interpreter exit when readline was already configured
# through a PYTHONSTARTUP hook, see:
# http://bugs.python.org/issue5845#msg198636
history = os.path.join(os.path.expanduser("~"), ".python_history")
try:
readline.read_history_file(history)
except OSError:
pass
def write_history():
try:
readline.write_history_file(history)
except (FileNotFoundError, PermissionError):
# home directory does not exist or is not writable
# https://bugs.python.org/issue19891
pass
atexit.register(write_history)
sys.__interactivehook__ = register_readline
if _is_pypy:
def import_builtin_stuff():
"""PyPy specific: some built-in modules should be pre-imported because
some programs expect them to be in sys.modules on startup. This is ported
from PyPy's site.py.
"""
import encodings
if "exceptions" in sys.builtin_module_names:
import exceptions
if "zipimport" in sys.builtin_module_names:
import zipimport
def main():
global ENABLE_USER_SITE
virtual_install_main_packages()
if _is_pypy:
import_builtin_stuff()
abs__file__()
paths_in_sys = removeduppaths()
if (os.name == "posix" and sys.path and
os.path.basename(sys.path[-1]) == "Modules"):
if os.name == "posix" and sys.path and os.path.basename(sys.path[-1]) == "Modules":
addbuilddir()
if _is_jython:
fixclasspath()
GLOBAL_SITE_PACKAGES = not os.path.exists(os.path.join(os.path.dirname(__file__), 'no-global-site-packages.txt'))
GLOBAL_SITE_PACKAGES = not os.path.exists(os.path.join(os.path.dirname(__file__), "no-global-site-packages.txt"))
if not GLOBAL_SITE_PACKAGES:
ENABLE_USER_SITE = False
if ENABLE_USER_SITE is None:
@ -684,11 +747,13 @@ def main():
paths_in_sys = addusersitepackages(paths_in_sys)
if GLOBAL_SITE_PACKAGES:
paths_in_sys = virtual_addsitepackages(paths_in_sys)
if sys.platform == 'os2emx':
if sys.platform == "os2emx":
setBEGINLIBPATH()
setquit()
setcopyright()
sethelper()
if sys.version_info[0] == 3:
enablerlcompleter()
aliasmbcs()
setencoding()
execsitecustomize()
@ -700,8 +765,10 @@ def main():
if hasattr(sys, "setdefaultencoding"):
del sys.setdefaultencoding
main()
def _script():
help = """\
%s [--user-base] [--user-site]
@ -721,22 +788,24 @@ def _script():
if not args:
print("sys.path = [")
for dir in sys.path:
print(" %r," % (dir,))
print(" {!r},".format(dir))
print("]")
def exists(path):
if os.path.isdir(path):
return "exists"
else:
return "doesn't exist"
print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE)))
print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE)))
print("ENABLE_USER_SITE: %r" % ENABLE_USER_SITE)
print("USER_BASE: {!r} ({})".format(USER_BASE, exists(USER_BASE)))
print("USER_SITE: {!r} ({})".format(USER_SITE, exists(USER_SITE)))
print("ENABLE_USER_SITE: %r" % ENABLE_USER_SITE)
sys.exit(0)
buffer = []
if '--user-base' in args:
if "--user-base" in args:
buffer.append(USER_BASE)
if '--user-site' in args:
if "--user-site" in args:
buffer.append(USER_SITE)
if buffer:
@ -751,8 +820,10 @@ def _script():
sys.exit(3)
else:
import textwrap
print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
sys.exit(10)
if __name__ == '__main__':
if __name__ == "__main__":
_script()