diff options
author | Bernát Gábor <gaborjbernat@gmail.com> | 2018-10-26 10:04:36 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-26 10:04:36 +0100 |
commit | 181b311349bf6dc26692e0693c2e000da6c071f6 (patch) | |
tree | 9ec28a1d98b333585b76b24803341f6ad7bda506 | |
parent | 6974665f6eaea0d1effeab0b684e3841ced62629 (diff) | |
parent | 249386088f9205cd399672a80428314229266751 (diff) | |
download | virtualenv-181b311349bf6dc26692e0693c2e000da6c071f6.tar.gz |
Merge pull request #1221 from pypa/lint
Add linter and code formatter
-rw-r--r-- | .gitattributes | 2 | ||||
-rw-r--r-- | .pre-commit-config.yaml | 43 | ||||
-rw-r--r-- | AUTHORS.txt | 3 | ||||
-rw-r--r-- | CONTRIBUTING.rst | 2 | ||||
-rw-r--r-- | README.rst | 18 | ||||
-rw-r--r-- | azure-pipelines.yml | 4 | ||||
-rwxr-xr-x | bin/rebuild-script.py | 59 | ||||
-rw-r--r-- | docs/changes.rst | 16 | ||||
-rw-r--r-- | docs/conf.py | 70 | ||||
-rw-r--r-- | docs/development.rst | 10 | ||||
-rw-r--r-- | docs/installation.rst | 2 | ||||
-rw-r--r-- | docs/userguide.rst | 3 | ||||
-rw-r--r-- | pyproject.toml | 3 | ||||
-rw-r--r-- | setup.py | 101 | ||||
-rwxr-xr-x | src/virtualenv.py | 1698 | ||||
-rw-r--r-- | tests/test_cmdline.py | 36 | ||||
-rw-r--r-- | tests/test_virtualenv.py | 287 | ||||
-rw-r--r-- | tox.ini | 28 | ||||
-rw-r--r-- | virtualenv_embedded/activate.csh | 1 | ||||
-rw-r--r-- | virtualenv_embedded/activate_this.py | 18 | ||||
-rw-r--r-- | virtualenv_embedded/deactivate.bat | 3 | ||||
-rw-r--r-- | virtualenv_embedded/distutils-init.py | 77 | ||||
-rw-r--r-- | virtualenv_embedded/site.py | 279 |
23 files changed, 1463 insertions, 1300 deletions
diff --git a/.gitattributes b/.gitattributes index 86c9df4..966b570 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -virtualenv_embedded/*.bat text eol=crlf
\ No newline at end of file +virtualenv_embedded/*.bat text eol=crlf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..01e2cad --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,43 @@ +repos: +- repo: https://github.com/ambv/black + rev: 18.9b0 + hooks: + - id: black + args: [--safe] + language_version: python3.7 +- repo: https://github.com/asottile/blacken-docs + rev: v0.3.0 + hooks: + - id: blacken-docs + additional_dependencies: [black==18.9b0] + language_version: python3.7 +- repo: https://github.com/gaborbernat/seed-isort-config + rev: master + hooks: + - id: seed-isort-config + args: [--application-directories, "src:tests:virtualenv_embedded"] +- repo: https://github.com/pre-commit/mirrors-isort + rev: v4.3.4 + hooks: + - id: isort +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: debug-statements + - id: check-merge-conflict + - id: trailing-whitespace + - id: check-docstring-first + - id: flake8 + additional_dependencies: ["flake8-bugbear == 18.8.0"] + language_version: python3.7 +- repo: https://github.com/asottile/pyupgrade + rev: v1.9.1 + hooks: + - id: pyupgrade +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.1.0 + hooks: + - id: rst-backticks diff --git a/AUTHORS.txt b/AUTHORS.txt index 2724941..ea68f33 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -7,6 +7,7 @@ Maintainers ----------- Brian Rosner +Bernat Gabor Carl Meyer Jannis Leidel Paul Moore @@ -88,4 +89,4 @@ Thomas Aglassinger Vinay Sajip Vitaly Babiy Vladimir Rutsky -Wang Xuerui
\ No newline at end of file +Wang Xuerui diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index a45bc4e..b0815ca 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -10,7 +10,7 @@ Contributor notes 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 +* Pull requests should be made against ``master`` branch, which is also our latest stable version. * All changes to files inside virtualenv_embedded should be integrated to @@ -4,10 +4,20 @@ virtualenv A tool for creating isolated 'virtual' python environments. .. image:: https://img.shields.io/pypi/v/virtualenv.svg - :target: https://pypi.org/project/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 + :target: https://dev.azure.com/pypa/virtualenv/_apis/build/status/pypa.virtualenv?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 * `Installation <https://virtualenv.pypa.io/en/latest/installation.html>`_ * `Documentation <https://virtualenv.pypa.io/>`_ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 36db607..07deb07 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,6 +21,8 @@ trigger: jobs: - template: azure-run-tox-env.yml + parameters: {tox: fix_lint, python: 3.7} +- template: azure-run-tox-env.yml parameters: {tox: embed, python: 3.7} - template: azure-run-tox-env.yml parameters: {tox: docs, python: 3.7} @@ -117,4 +119,4 @@ jobs: codeCoverageTool: 'cobertura' summaryFileLocation: '$(System.DefaultWorkingDirectory)/.tox/coverage.xml' reportDirectory: '$(System.DefaultWorkingDirectory)/.tox/htmlcov' - failIfCoverageEmpty: true
\ No newline at end of file + failIfCoverageEmpty: true diff --git a/bin/rebuild-script.py b/bin/rebuild-script.py index 7066bb6..5361210 100755 --- a/bin/rebuild-script.py +++ b/bin/rebuild-script.py @@ -4,80 +4,77 @@ Helper script to rebuild virtualenv.py from virtualenv_support """ from __future__ import print_function +import codecs import os import re -import codecs from zlib import crc32 as _crc32 def crc32(data): """Python version idempotent""" - return _crc32(data) & 0xffffffff + return _crc32(data) & 0xFFFFFFFF here = os.path.dirname(__file__) -script = os.path.join(here, '..', 'src', 'virtualenv.py') +script = os.path.join(here, "..", "src", "virtualenv.py") -gzip = codecs.lookup('zlib') -b64 = codecs.lookup('base64') +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""")' +file_regex = re.compile(br'# file (.*?)\n([a-zA-Z][a-zA-Z0-9_]+) = convert\(\n """\n(.*?)"""\n\)', re.S) +file_template = b'# file %(filename)s\n%(variable)s = convert(\n """\n%(data)s"""\n)' def rebuild(script_path): exit_code = 0 - with open(script_path, 'rb') as f: + 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()]] + _count = 0 + for _count, match in enumerate(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) + variable = match.group(2) data = match.group(3) - print('Found file %s' % fn_decoded) - pathname = os.path.join(here, '..', 'virtualenv_embedded', fn_decoded) + print("Found file %s" % fn_decoded) + pathname = os.path.join(here, "..", "virtualenv_embedded", fn_decoded) - with open(pathname, 'rb') as f: + 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) + print(" File up to date (crc: %08x)" % new_crc) parts += [match.group(0)] continue exit_code = 1 # 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 - } + print(" Content changed (crc: {:08x} -> {:08x})".format(crc, new_crc)) + new_match = file_template % {b"filename": filename, b"variable": variable, b"data": new_data} parts += [new_match] parts += [script_content[last_pos:]] - new_content = b''.join(parts) + new_content = b"".join(parts) if new_content != script_content: - print('Content updated; overwriting... ', end='') - with open(script_path, 'wb') as f: + print("Content updated; overwriting... ", end="") + with open(script_path, "wb") as f: f.write(new_content) - print('done.') + print("done.") else: - print('No changes in content') + print("No changes in content") if match is None: - print('No variables were matched/found') + print("No variables were matched/found") + if not _count: + exit_code = 1 raise SystemExit(exit_code) -if __name__ == '__main__': + +if __name__ == "__main__": rebuild(script) diff --git a/docs/changes.rst b/docs/changes.rst index 5b5bb4e..6b0bc00 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -75,7 +75,7 @@ Release History 15.0.0 (2016-03-05) ------------------- -* Remove the `virtualenv-N.N` script from the package; this can no longer be +* Remove the ``virtualenv-N.N`` script from the package; this can no longer be correctly created from a wheel installation. Resolves :issue:`851`, :issue:`692` @@ -124,7 +124,7 @@ Release History * Upgrade setuptools to 19.6 -* Supress any errors from `unset` on different shells (:pull:`843`) +* Suppress any errors from ``unset`` on different shells (:pull:`843`) * Normalize letter case for prefix path checking. Fixes :issue:`837` @@ -485,7 +485,7 @@ Release History 1.8.1 (2012-09-03) ------------------ -* Fixed distribute version used with `--never-download`. Thanks michr for +* Fixed distribute version used with ``--never-download``. Thanks michr for report and patch. * Fix creating Python 3.3 based virtualenvs by unsetting the @@ -498,7 +498,7 @@ Release History * **Dropped support for Python 2.4** The minimum supported Python version is now Python 2.5. -* Fix `--relocatable` on systems that use lib64. Fixes #78. Thanks Branden +* Fix ``--relocatable`` on systems that use lib64. Fixes #78. Thanks Branden Rolston. * Symlink some additional modules under Python 3. Fixes #194. Thanks Vinay @@ -556,7 +556,7 @@ Release History 1.7.1.2 (2012-02-17) -------------------- -* Fixed minor issue in `--relocatable`. Thanks, Cap Petschulat. +* Fixed minor issue in ``--relocatable``. Thanks, Cap Petschulat. 1.7.1.1 (2012-02-16) @@ -572,7 +572,7 @@ Release History * Update embedded pip to version 1.1. -* Fix `--relocatable` under Python 3. Thanks Doug Hellmann. +* Fix ``--relocatable`` under Python 3. Thanks Doug Hellmann. * Added environ PATH modification to activate_this.py. Thanks Doug Napoleone. Fixes #14. @@ -592,8 +592,8 @@ Release History Napoleone for testing and confirmation. Fixes #87. * Fixed creation of virtualenvs using -p in installs where some modules - that ought to be in the standard library (e.g. `readline`) are actually - installed in `site-packages` next to `virtualenv.py`. Thanks Greg Haskins + that ought to be in the standard library (e.g. ``readline``) are actually + installed in ``site-packages`` next to ``virtualenv.py``. Thanks Greg Haskins for report and fix. Fixes #167. * Added activation script for Powershell (signed by Jannis Leidel). Many diff --git a/docs/conf.py b/docs/conf.py index 9332aa1..36cf58a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,7 @@ import os import sys -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" # If your extensions are in another directory, add it here. sys.path.insert(0, os.path.abspath(os.pardir)) @@ -24,58 +24,59 @@ sys.path.insert(0, os.path.abspath(os.pardir)) # 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'] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.extlinks"] # Add any paths that contain templates here, relative to this directory. -#templates_path = ['_templates'] +# templates_path = ['_templates'] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General substitutions. -project = 'virtualenv' -copyright = '2007-2014, Ian Bicking, The Open Planning Project, PyPA' +project = "virtualenv" +copyright = "2007-2014, Ian Bicking, The Open Planning Project, PyPA" # 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]) + version = ".".join(__version__.split(".")[:2]) # The full version, including alpha/beta/rc tags. release = __version__ except ImportError: - version = release = 'dev' + version = release = "dev" # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -today_fmt = '%B %d, %Y' +today_fmt = "%B %d, %Y" # List of documents that shouldn't be included in the build. unused_docs = [] # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# 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 +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" 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 #"), } @@ -85,13 +86,14 @@ extlinks = { # 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_style = 'default.css' -html_theme = 'default' +html_theme = "default" if not on_rtd: try: import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' + + html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] except ImportError: pass @@ -104,50 +106,50 @@ if not on_rtd: # 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' +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 +# html_use_smartypants = True # Content template for the index page. -#html_index = '' +# html_index = '' # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_use_modindex = True +# html_use_modindex = True # If true, the reST sources are included in the HTML build as _sources/<name>. -#html_copy_source = True +# html_copy_source = True # Output file base name for HTML help builder. -htmlhelp_basename = 'Pastedoc' +htmlhelp_basename = "Pastedoc" # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# 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 = [] +# latex_documents = [] # Additional stuff for the LaTeX preamble. -#latex_preamble = '' +# latex_preamble = '' # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_use_modindex = True +# latex_use_modindex = True diff --git a/docs/development.rst b/docs/development.rst index d60f5a8..ea216ea 100644 --- a/docs/development.rst +++ b/docs/development.rst @@ -12,11 +12,11 @@ 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 +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. .. _pip development: https://pip.pypa.io/en/latest/development/ diff --git a/docs/installation.rst b/docs/installation.rst index a99ff5a..7e6a97d 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -17,7 +17,7 @@ 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): +To install globally with ``pip`` (if you have pip 1.3 or greater installed globally): :: diff --git a/docs/userguide.rst b/docs/userguide.rst index dc594d3..ca761d2 100644 --- a/docs/userguide.rst +++ b/docs/userguide.rst @@ -65,7 +65,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 @@ -255,4 +255,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. - diff --git a/pyproject.toml b/pyproject.toml index c70af8c..211cf02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,3 +4,6 @@ requires = [ "wheel >= 0.29.0", ] build-backend = 'setuptools.build_meta' + +[tool.black] +line-length = 120 @@ -3,13 +3,13 @@ import re import sys if sys.version_info[:2] < (2, 7): - sys.exit('virtualenv requires Python 2.7 or higher.') + sys.exit("virtualenv requires Python 2.7 or higher.") try: from setuptools import setup, find_packages from setuptools.command.test import test as TestCommand class PyTest(TestCommand): - user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")] + user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] def initialize_options(self): TestCommand.initialize_options(self) @@ -17,31 +17,30 @@ try: def finalize_options(self): TestCommand.finalize_options(self) - #self.test_args = [] - #self.test_suite = True + # 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'], + "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"') + + if sys.platform == "win32": + print("Note: without Setuptools installed you will " 'have to use "python -m virtualenv ENV"') setup_params = {} else: - script = 'src/scripts/virtualenv' - setup_params = {'scripts': [script]} + script = "src/scripts/virtualenv" + setup_params = {"scripts": [script]} def read_file(*paths): @@ -51,33 +50,32 @@ def read_file(*paths): # Get long_description from index.rst: -long_description_full = read_file('docs', 'index.rst') -long_description = long_description_full.strip().split('split here', 1)[0] +long_description_full = read_file("docs", "index.rst") +long_description = long_description_full.strip().split("split here", 1)[0] # Add release history -changes = read_file('docs', 'changes.rst') +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('--------------'): + 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>`_.' +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) +changes = re.sub(r":pull:`(\d+)`", r"PR #\1", changes) +changes = re.sub(r":issue:`(\d+)`", r"#\1", changes) -long_description += '\n\n' + changes +long_description += "\n\n" + changes def get_version(): - version_file = read_file(os.path.join('src', 'virtualenv.py')) - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", - version_file, re.M) + version_file = read_file(os.path.join("src", "virtualenv.py")) + 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.") @@ -93,32 +91,33 @@ except ImportError: pass setup( - name='virtualenv', + 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.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', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "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", ], - 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', - package_dir={'': 'src'}, - py_modules=['virtualenv'], - packages=find_packages('src'), - package_data={'virtualenv_support': ['*.whl']}, - python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', - **setup_params) + 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", + package_dir={"": "src"}, + py_modules=["virtualenv"], + packages=find_packages("src"), + package_data={"virtualenv_support": ["*.whl"]}, + python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*", + **setup_params +) diff --git a/src/virtualenv.py b/src/virtualenv.py index 8839343..e814484 100755 --- a/src/virtualenv.py +++ b/src/virtualenv.py @@ -1,34 +1,36 @@ #!/usr/bin/env python """Create a "virtual" Python installation""" -import os -import sys +# fmt: off +import os # isort:skip +import sys # isort:skip # If we are running in a new interpreter to create a virtualenv, # we do NOT want paths from our existing location interfering with anything, # So we remove this file's directory from sys.path - most likely to be # the previous interpreter's site-packages. Solves #705, #763, #779 -if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): +if os.environ.get("VIRTUALENV_INTERPRETER_RUNNING"): for path in sys.path[:]: if os.path.realpath(os.path.dirname(__file__)) == os.path.realpath(path): sys.path.remove(path) +# fmt: on import base64 import codecs +import distutils.spawn +import distutils.sysconfig +import errno +import glob +import logging import optparse +import os import re import shutil -import logging -import zlib -import errno -import glob -import distutils.spawn -import distutils.sysconfig import struct import subprocess -import pkgutil -import tempfile +import sys import textwrap +import zlib from distutils.util import strtobool from os.path import join @@ -41,8 +43,8 @@ __version__ = "16.1.0.dev0" virtualenv_version = __version__ # legacy if sys.version_info < (2, 7): - print('ERROR: %s' % sys.exc_info()[1]) - print('ERROR: this script requires Python 2.7 or greater.') + print("ERROR: %s" % sys.exc_info()[1]) + print("ERROR: this script requires Python 2.7 or greater.") sys.exit(101) try: @@ -50,34 +52,37 @@ try: except NameError: basestring = str -py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1]) +py_version = "python{}.{}".format(sys.version_info[0], sys.version_info[1]) -is_jython = sys.platform.startswith('java') -is_pypy = hasattr(sys, 'pypy_version_info') -is_win = (sys.platform == 'win32') -is_cygwin = (sys.platform == 'cygwin') -is_darwin = (sys.platform == 'darwin') -abiflags = getattr(sys, 'abiflags', '') +is_jython = sys.platform.startswith("java") +is_pypy = hasattr(sys, "pypy_version_info") +is_win = sys.platform == "win32" +is_cygwin = sys.platform == "cygwin" +is_darwin = sys.platform == "darwin" +abiflags = getattr(sys, "abiflags", "") -user_dir = os.path.expanduser('~') +user_dir = os.path.expanduser("~") if is_win: - default_storage_dir = os.path.join(user_dir, 'virtualenv') + default_storage_dir = os.path.join(user_dir, "virtualenv") else: - default_storage_dir = os.path.join(user_dir, '.virtualenv') -default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini') + default_storage_dir = os.path.join(user_dir, ".virtualenv") +default_config_file = os.path.join(default_storage_dir, "virtualenv.ini") if is_pypy: - expected_exe = 'pypy' + expected_exe = "pypy" elif is_jython: - expected_exe = 'jython' + expected_exe = "jython" else: - expected_exe = 'python' + expected_exe = "python" # Return a mapping of version -> Python executable # Only provided for Windows, where the information in the registry is used if not is_win: + def get_installed_pythons(): return {} + + else: try: import winreg @@ -90,8 +95,7 @@ else: # particular Python version, the current user one is used for key in (winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER): try: - python_core = winreg.CreateKey(key, - "Software\\Python\\PythonCore") + python_core = winreg.CreateKey(key, "Software\\Python\\PythonCore") except WindowsError: # No registered Python installations continue @@ -101,8 +105,7 @@ else: version = winreg.EnumKey(python_core, i) i += 1 try: - path = winreg.QueryValue(python_core, - "%s\\InstallPath" % version) + path = winreg.QueryValue(python_core, "%s\\InstallPath" % version) except WindowsError: continue exes[version] = join(path, "python.exe") @@ -116,14 +119,14 @@ else: # available or 32-bit if it is not updated = {} for ver in exes: - if ver < '3.5': + if ver < "3.5": continue - if ver.endswith('-32'): + if ver.endswith("-32"): base_ver = ver[:-3] if base_ver not in exes: updated[base_ver] = exes[ver] else: - updated[ver + '-64'] = exes[ver] + updated[ver + "-64"] = exes[ver] exes.update(updated) # Add the major versions @@ -135,57 +138,91 @@ else: return exes -REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath', - 'fnmatch', 'locale', 'encodings', 'codecs', - 'stat', 'UserDict', 'readline', 'copy_reg', 'types', - 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile', - 'zlib'] -REQUIRED_FILES = ['lib-dynload', 'config'] +REQUIRED_MODULES = [ + "os", + "posix", + "posixpath", + "nt", + "ntpath", + "genericpath", + "fnmatch", + "locale", + "encodings", + "codecs", + "stat", + "UserDict", + "readline", + "copy_reg", + "types", + "re", + "sre", + "sre_parse", + "sre_constants", + "sre_compile", + "zlib", +] + +REQUIRED_FILES = ["lib-dynload", "config"] majver, minver = sys.version_info[:2] if majver == 2: if minver >= 6: - REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc']) + REQUIRED_MODULES.extend(["warnings", "linecache", "_abcoll", "abc"]) if minver >= 7: - REQUIRED_MODULES.extend(['_weakrefset']) + REQUIRED_MODULES.extend(["_weakrefset"]) elif majver == 3: # Some extra modules are needed for Python 3, but different ones # for different versions. - REQUIRED_MODULES.extend([ - '_abcoll', 'warnings', 'linecache', 'abc', 'io', '_weakrefset', - 'copyreg', 'tempfile', 'random', '__future__', 'collections', - 'keyword', 'tarfile', 'shutil', 'struct', 'copy', 'tokenize', - 'token', 'functools', 'heapq', 'bisect', 'weakref', 'reprlib' - ]) + REQUIRED_MODULES.extend( + [ + "_abcoll", + "warnings", + "linecache", + "abc", + "io", + "_weakrefset", + "copyreg", + "tempfile", + "random", + "__future__", + "collections", + "keyword", + "tarfile", + "shutil", + "struct", + "copy", + "tokenize", + "token", + "functools", + "heapq", + "bisect", + "weakref", + "reprlib", + ] + ) if minver >= 2: - REQUIRED_FILES[-1] = 'config-%s' % majver + REQUIRED_FILES[-1] = "config-%s" % majver if minver >= 3: import sysconfig - platdir = sysconfig.get_config_var('PLATDIR') + + platdir = sysconfig.get_config_var("PLATDIR") REQUIRED_FILES.append(platdir) - REQUIRED_MODULES.extend([ - 'base64', '_dummy_thread', 'hashlib', 'hmac', - 'imp', 'importlib', 'rlcompleter' - ]) + REQUIRED_MODULES.extend(["base64", "_dummy_thread", "hashlib", "hmac", "imp", "importlib", "rlcompleter"]) if minver >= 4: - REQUIRED_MODULES.extend([ - 'operator', - '_collections_abc', - '_bootlocale', - ]) + REQUIRED_MODULES.extend(["operator", "_collections_abc", "_bootlocale"]) if minver >= 6: - REQUIRED_MODULES.extend(['enum']) + REQUIRED_MODULES.extend(["enum"]) if is_pypy: # these are needed to correctly display the exceptions that may happen # during the bootstrap - REQUIRED_MODULES.extend(['traceback', 'linecache']) + REQUIRED_MODULES.extend(["traceback", "linecache"]) if majver == 3: # _functools is needed to import locale during stdio initialization and # needs to be copied on PyPy because it's not built in - REQUIRED_MODULES.append('_functools') + REQUIRED_MODULES.append("_functools") class Logger(object): @@ -197,7 +234,7 @@ class Logger(object): DEBUG = logging.DEBUG INFO = logging.INFO - NOTIFY = (logging.INFO+logging.WARN)/2 + NOTIFY = (logging.INFO + logging.WARN) / 2 WARN = WARNING = logging.WARN ERROR = logging.ERROR FATAL = logging.FATAL @@ -231,32 +268,30 @@ class Logger(object): def log(self, level, msg, *args, **kw): if args: if kw: - raise TypeError( - "You may give positional or keyword arguments, not both") + raise TypeError("You may give positional or keyword arguments, not both") args = args or kw rendered = None for consumer_level, consumer in self.consumers: if self.level_matches(level, consumer_level): - if (self.in_progress_hanging - and consumer in (sys.stdout, sys.stderr)): + if self.in_progress_hanging and consumer in (sys.stdout, sys.stderr): self.in_progress_hanging = False - sys.stdout.write('\n') + sys.stdout.write("\n") sys.stdout.flush() if rendered is None: if args: rendered = msg % args else: rendered = msg - rendered = ' '*self.indent + rendered - if hasattr(consumer, 'write'): - consumer.write(rendered+'\n') + rendered = " " * self.indent + rendered + if hasattr(consumer, "write"): + consumer.write(rendered + "\n") else: consumer(rendered) def start_progress(self, msg): - assert not self.in_progress, ( - "Tried to start_progress(%r) while in_progress %r" - % (msg, self.in_progress)) + assert not self.in_progress, "Tried to start_progress({!r}) while in_progress {!r}".format( + msg, self.in_progress + ) if self.level_matches(self.NOTIFY, self._stdout_level()): sys.stdout.write(msg) sys.stdout.flush() @@ -265,16 +300,15 @@ class Logger(object): self.in_progress_hanging = False self.in_progress = msg - def end_progress(self, msg='done.'): - assert self.in_progress, ( - "Tried to end_progress without start_progress") + def end_progress(self, msg="done."): + assert self.in_progress, "Tried to end_progress without start_progress" if self.stdout_level_matches(self.NOTIFY): if not self.in_progress_hanging: # Some message has been printed out since start_progress - sys.stdout.write('...' + self.in_progress + msg + '\n') + sys.stdout.write("..." + self.in_progress + msg + "\n") sys.stdout.flush() else: - sys.stdout.write(msg + '\n') + sys.stdout.write(msg + "\n") sys.stdout.flush() self.in_progress = None self.in_progress_hanging = False @@ -283,7 +317,7 @@ class Logger(object): """If we are in a progress scope, and no log messages have been shown, write out another '.'""" if self.in_progress_hanging: - sys.stdout.write('.') + sys.stdout.write(".") sys.stdout.flush() def stdout_level_matches(self, level): @@ -332,16 +366,19 @@ class Logger(object): return levels[-1] return levels[level] + # create a silent logger just to prevent this from being undefined # will be overridden with requested verbosity main() is called. logger = Logger([(Logger.LEVELS[-1], sys.stdout)]) + def mkdir(path): if not os.path.exists(path): - logger.info('Creating %s', path) + logger.info("Creating %s", path) os.makedirs(path) else: - logger.info('Directory %s already exists', path) + logger.info("Directory %s already exists", path) + def copyfileordir(src, dest, symlink=True): if os.path.isdir(src): @@ -349,64 +386,69 @@ def copyfileordir(src, dest, symlink=True): else: shutil.copy2(src, dest) + def copyfile(src, dest, symlink=True): if not os.path.exists(src): # Some bad symlink in the src - logger.warn('Cannot find file %s (bad symlink)', src) + logger.warn("Cannot find file %s (bad symlink)", src) return if os.path.exists(dest): - logger.debug('File %s already exists', dest) + logger.debug("File %s already exists", dest) return if not os.path.exists(os.path.dirname(dest)): - logger.info('Creating parent directories for %s', os.path.dirname(dest)) + logger.info("Creating parent directories for %s", os.path.dirname(dest)) os.makedirs(os.path.dirname(dest)) if not os.path.islink(src): srcpath = os.path.abspath(src) else: srcpath = os.readlink(src) - if symlink and hasattr(os, 'symlink') and not is_win: - logger.info('Symlinking %s', dest) + if symlink and hasattr(os, "symlink") and not is_win: + logger.info("Symlinking %s", dest) try: os.symlink(srcpath, dest) except (OSError, NotImplementedError): - logger.info('Symlinking failed, copying to %s', dest) + logger.info("Symlinking failed, copying to %s", dest) copyfileordir(src, dest, symlink) else: - logger.info('Copying to %s', dest) + logger.info("Copying to %s", dest) copyfileordir(src, dest, symlink) + def writefile(dest, content, overwrite=True): if not os.path.exists(dest): - logger.info('Writing %s', dest) - with open(dest, 'wb') as f: - f.write(content.encode('utf-8')) + logger.info("Writing %s", dest) + with open(dest, "wb") as f: + f.write(content.encode("utf-8")) return else: - with open(dest, 'rb') as f: + with open(dest, "rb") as f: c = f.read() if c != content.encode("utf-8"): if not overwrite: - logger.notify('File %s exists with different content; not overwriting', dest) + logger.notify("File %s exists with different content; not overwriting", dest) return - logger.notify('Overwriting %s with new content', dest) - with open(dest, 'wb') as f: - f.write(content.encode('utf-8')) + logger.notify("Overwriting %s with new content", dest) + with open(dest, "wb") as f: + f.write(content.encode("utf-8")) else: - logger.info('Content %s already in place', dest) + logger.info("Content %s already in place", dest) + def rmtree(dir): if os.path.exists(dir): - logger.notify('Deleting tree %s', dir) + logger.notify("Deleting tree %s", dir) shutil.rmtree(dir) else: - logger.info('Do not need to delete %s; already gone', dir) + logger.info("Do not need to delete %s; already gone", dir) + def make_exe(fn): - if hasattr(os, 'chmod'): - oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777 - newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777 + if hasattr(os, "chmod"): + oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777 + newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777 os.chmod(fn, newmode) - logger.info('Changed mode of %s to %s', fn, oct(newmode)) + logger.info("Changed mode of %s to %s", fn, oct(newmode)) + def _find_file(filename, dirs): for dir in reversed(dirs): @@ -415,18 +457,18 @@ def _find_file(filename, dirs): return True, files[0] return False, filename + def file_search_dirs(): here = os.path.dirname(os.path.abspath(__file__)) - dirs = [here, join(here, 'virtualenv_support')] - if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv': + dirs = [here, join(here, "virtualenv_support")] + if os.path.splitext(os.path.dirname(__file__))[0] != "virtualenv": # Probably some boot script; just in case virtualenv is installed... try: import virtualenv except ImportError: pass else: - dirs.append(os.path.join( - os.path.dirname(virtualenv.__file__), 'virtualenv_support')) + dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), "virtualenv_support")) return [d for d in dirs if os.path.isdir(d)] @@ -436,6 +478,7 @@ class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter): the defaults before expanding them, allowing them to show up correctly in the help listing """ + def expand_default(self, option): if self.parser is not None: self.parser.update_defaults(self.parser.defaults) @@ -447,6 +490,7 @@ class ConfigOptionParser(optparse.OptionParser): Custom option parser which updates its defaults by checking the configuration files and environmental variables """ + def __init__(self, *args, **kwargs): self.config = ConfigParser.RawConfigParser() self.files = self.get_config_files() @@ -454,7 +498,7 @@ class ConfigOptionParser(optparse.OptionParser): optparse.OptionParser.__init__(self, *args, **kwargs) def get_config_files(self): - config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False) + config_file = os.environ.get("VIRTUALENV_CONFIG_FILE", False) if config_file and os.path.exists(config_file): return [config_file] return [default_config_file] @@ -468,27 +512,27 @@ class ConfigOptionParser(optparse.OptionParser): # Then go and look for the other sources of configuration: config = {} # 1. config files - config.update(dict(self.get_config_section('virtualenv'))) + config.update(dict(self.get_config_section("virtualenv"))) # 2. environmental variables config.update(dict(self.get_environ_vars())) # Then set the options with those values for key, val in config.items(): - key = key.replace('_', '-') - if not key.startswith('--'): - key = '--%s' % key # only prefer long opts + key = key.replace("_", "-") + if not key.startswith("--"): + key = "--%s" % key # only prefer long opts option = self.get_option(key) if option is not None: # ignore empty values if not val: continue # handle multiline configs - if option.action == 'append': + if option.action == "append": val = val.split() else: option.nargs = 1 - if option.action == 'store_false': + if option.action == "store_false": val = not strtobool(val) - elif option.action in ('store_true', 'count'): + elif option.action in ("store_true", "count"): val = strtobool(val) try: val = option.convert_value(key, val) @@ -507,13 +551,13 @@ class ConfigOptionParser(optparse.OptionParser): return self.config.items(name) return [] - def get_environ_vars(self, prefix='VIRTUALENV_'): + def get_environ_vars(self, prefix="VIRTUALENV_"): """ Returns a generator with all environmental vars with prefix VIRTUALENV """ for key, val in os.environ.items(): if key.startswith(prefix): - yield (key.replace(prefix, '').lower(), val) + yield (key.replace(prefix, "").lower(), val) def get_default_values(self): """ @@ -535,93 +579,81 @@ class ConfigOptionParser(optparse.OptionParser): def main(): parser = ConfigOptionParser( - version=virtualenv_version, - usage="%prog [OPTIONS] DEST_DIR", - formatter=UpdatingDefaultsHelpFormatter()) + version=virtualenv_version, usage="%prog [OPTIONS] DEST_DIR", formatter=UpdatingDefaultsHelpFormatter() + ) - parser.add_option( - '-v', '--verbose', - action='count', - dest='verbose', - default=0, - help="Increase verbosity.") + parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0, help="Increase verbosity.") - parser.add_option( - '-q', '--quiet', - action='count', - dest='quiet', - default=0, - help='Decrease verbosity.') + parser.add_option("-q", "--quiet", action="count", dest="quiet", default=0, help="Decrease verbosity.") parser.add_option( - '-p', '--python', - dest='python', - metavar='PYTHON_EXE', - help='The Python interpreter to use, e.g., --python=python3.5 will use the python3.5 ' - 'interpreter to create the new environment. The default is the interpreter that ' - 'virtualenv was installed with (%s)' % sys.executable) + "-p", + "--python", + dest="python", + metavar="PYTHON_EXE", + help="The Python interpreter to use, e.g., --python=python3.5 will use the python3.5 " + "interpreter to create the new environment. The default is the interpreter that " + "virtualenv was installed with (%s)" % sys.executable, + ) parser.add_option( - '--clear', - dest='clear', - action='store_true', - help="Clear out the non-root install and start from scratch.") + "--clear", dest="clear", action="store_true", help="Clear out the non-root install and start from scratch." + ) parser.set_defaults(system_site_packages=False) parser.add_option( - '--no-site-packages', - dest='system_site_packages', - action='store_false', + "--no-site-packages", + dest="system_site_packages", + action="store_false", help="DEPRECATED. Retained only for backward compatibility. " - "Not having access to global site-packages is now the default behavior.") + "Not having access to global site-packages is now the default behavior.", + ) parser.add_option( - '--system-site-packages', - dest='system_site_packages', - action='store_true', - help="Give the virtual environment access to the global site-packages.") + "--system-site-packages", + dest="system_site_packages", + action="store_true", + help="Give the virtual environment access to the global site-packages.", + ) parser.add_option( - '--always-copy', - dest='symlink', - action='store_false', + "--always-copy", + dest="symlink", + action="store_false", default=True, - help="Always copy files rather than symlinking.") + help="Always copy files rather than symlinking.", + ) parser.add_option( - '--relocatable', - dest='relocatable', - action='store_true', - help='Make an EXISTING virtualenv environment relocatable. ' - 'This fixes up scripts and makes all .pth files relative.') + "--relocatable", + dest="relocatable", + action="store_true", + help="Make an EXISTING virtualenv environment relocatable. " + "This fixes up scripts and makes all .pth files relative.", + ) parser.add_option( - '--no-setuptools', - dest='no_setuptools', - action='store_true', - help='Do not install setuptools in the new virtualenv.') + "--no-setuptools", + dest="no_setuptools", + action="store_true", + help="Do not install setuptools in the new virtualenv.", + ) - parser.add_option( - '--no-pip', - dest='no_pip', - action='store_true', - help='Do not install pip in the new virtualenv.') + parser.add_option("--no-pip", dest="no_pip", action="store_true", help="Do not install pip in the new virtualenv.") parser.add_option( - '--no-wheel', - dest='no_wheel', - action='store_true', - help='Do not install wheel in the new virtualenv.') + "--no-wheel", dest="no_wheel", action="store_true", help="Do not install wheel in the new virtualenv." + ) default_search_dirs = file_search_dirs() parser.add_option( - '--extra-search-dir', + "--extra-search-dir", dest="search_dirs", action="append", - metavar='DIR', + metavar="DIR", default=default_search_dirs, - help="Directory to look for setuptools/pip distributions in. " - "This option can be used multiple times.") + help="Directory to look for setuptools/pip distributions in. " "This option can be used multiple times.", + ) parser.add_option( "--download", @@ -633,121 +665,129 @@ def main(): parser.add_option( "--no-download", - '--never-download', + "--never-download", dest="download", action="store_false", help="Do not download preinstalled packages from PyPI.", ) - parser.add_option( - '--prompt', - dest='prompt', - help='Provides an alternative prompt prefix for this environment.') + parser.add_option("--prompt", dest="prompt", help="Provides an alternative prompt prefix for this environment.") parser.add_option( - '--setuptools', - dest='setuptools', - action='store_true', - help="DEPRECATED. Retained only for backward compatibility. This option has no effect.") + "--setuptools", + dest="setuptools", + action="store_true", + help="DEPRECATED. Retained only for backward compatibility. This option has no effect.", + ) parser.add_option( - '--distribute', - dest='distribute', - action='store_true', - help="DEPRECATED. Retained only for backward compatibility. This option has no effect.") + "--distribute", + dest="distribute", + action="store_true", + help="DEPRECATED. Retained only for backward compatibility. This option has no effect.", + ) parser.add_option( - '--unzip-setuptools', - action='store_true', - help="DEPRECATED. Retained only for backward compatibility. This option has no effect.") + "--unzip-setuptools", + action="store_true", + help="DEPRECATED. Retained only for backward compatibility. This option has no effect.", + ) - if 'extend_parser' in globals(): - extend_parser(parser) + if "extend_parser" in globals(): + extend_parser(parser) # noqa: F821 options, args = parser.parse_args() global logger - if 'adjust_options' in globals(): - adjust_options(options, args) + if "adjust_options" in globals(): + adjust_options(options, args) # noqa: F821 verbosity = options.verbose - options.quiet logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)]) - if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): + if options.python and not os.environ.get("VIRTUALENV_INTERPRETER_RUNNING"): env = os.environ.copy() interpreter = resolve_interpreter(options.python) if interpreter == sys.executable: - logger.warn('Already using interpreter %s' % interpreter) + logger.warn("Already using interpreter %s" % interpreter) else: - logger.notify('Running virtualenv with interpreter %s' % interpreter) - env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true' + logger.notify("Running virtualenv with interpreter %s" % interpreter) + env["VIRTUALENV_INTERPRETER_RUNNING"] = "true" file = __file__ - if file.endswith('.pyc'): + if file.endswith(".pyc"): file = file[:-1] popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env) raise SystemExit(popen.wait()) if not args: - print('You must provide a DEST_DIR') + print("You must provide a DEST_DIR") parser.print_help() sys.exit(2) if len(args) > 1: - print('There must be only one argument: DEST_DIR (you gave %s)' % ( - ' '.join(args))) + print("There must be only one argument: DEST_DIR (you gave %s)" % (" ".join(args))) parser.print_help() sys.exit(2) home_dir = args[0] if os.path.exists(home_dir) and os.path.isfile(home_dir): - logger.fatal('ERROR: File already exists and is not a directory.') - logger.fatal('Please provide a different path or delete the file.') + logger.fatal("ERROR: File already exists and is not a directory.") + logger.fatal("Please provide a different path or delete the file.") sys.exit(3) - if os.environ.get('WORKING_ENV'): - logger.fatal('ERROR: you cannot run virtualenv while in a workingenv') - logger.fatal('Please deactivate your workingenv, then re-run this script') + if os.environ.get("WORKING_ENV"): + logger.fatal("ERROR: you cannot run virtualenv while in a workingenv") + logger.fatal("Please deactivate your workingenv, then re-run this script") sys.exit(3) - if 'PYTHONHOME' in os.environ: - logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it') - del os.environ['PYTHONHOME'] + if "PYTHONHOME" in os.environ: + logger.warn("PYTHONHOME is set. You *must* activate the virtualenv before using it") + del os.environ["PYTHONHOME"] if options.relocatable: make_environment_relocatable(home_dir) return - create_environment(home_dir, - site_packages=options.system_site_packages, - clear=options.clear, - prompt=options.prompt, - search_dirs=options.search_dirs, - download=options.download, - no_setuptools=options.no_setuptools, - no_pip=options.no_pip, - no_wheel=options.no_wheel, - symlink=options.symlink) - if 'after_install' in globals(): - after_install(options, home_dir) - -def call_subprocess(cmd, show_stdout=True, - filter_stdout=None, cwd=None, - raise_on_returncode=True, extra_env=None, - remove_from_env=None, stdin=None): + create_environment( + home_dir, + site_packages=options.system_site_packages, + clear=options.clear, + prompt=options.prompt, + search_dirs=options.search_dirs, + download=options.download, + no_setuptools=options.no_setuptools, + no_pip=options.no_pip, + no_wheel=options.no_wheel, + symlink=options.symlink, + ) + if "after_install" in globals(): + after_install(options, home_dir) # noqa: F821 + + +def call_subprocess( + cmd, + show_stdout=True, + filter_stdout=None, + cwd=None, + raise_on_returncode=True, + extra_env=None, + remove_from_env=None, + stdin=None, +): cmd_parts = [] for part in cmd: if len(part) > 45: - part = part[:20]+"..."+part[-20:] - if ' ' in part or '\n' in part or '"' in part or "'" in part: + part = part[:20] + "..." + part[-20:] + if " " in part or "\n" in part or '"' in part or "'" in part: part = '"%s"' % part.replace('"', '\\"') - if hasattr(part, 'decode'): + if hasattr(part, "decode"): try: part = part.decode(sys.getdefaultencoding()) except UnicodeDecodeError: part = part.decode(sys.getfilesystemencoding()) cmd_parts.append(part) - cmd_desc = ' '.join(cmd_parts) + cmd_desc = " ".join(cmd_parts) if show_stdout: stdout = None else: @@ -764,14 +804,16 @@ def call_subprocess(cmd, show_stdout=True, env = None try: proc = subprocess.Popen( - cmd, stderr=subprocess.STDOUT, + cmd, + stderr=subprocess.STDOUT, stdin=None if stdin is None else subprocess.PIPE, stdout=stdout, - cwd=cwd, env=env) + cwd=cwd, + env=env, + ) except Exception: e = sys.exc_info()[1] - logger.fatal( - "Error %s while executing command %s" % (e, cmd_desc)) + logger.fatal("Error {} while executing command {}".format(e, cmd_desc)) raise all_output = [] if stdout is not None: @@ -807,21 +849,19 @@ def call_subprocess(cmd, show_stdout=True, if proc.returncode: if raise_on_returncode: if all_output: - logger.notify('Complete output from command %s:' % cmd_desc) - logger.notify('\n'.join(all_output) + '\n----------------------------------------') - raise OSError( - "Command %s failed with error code %s" - % (cmd_desc, proc.returncode)) + logger.notify("Complete output from command %s:" % cmd_desc) + logger.notify("\n".join(all_output) + "\n----------------------------------------") + raise OSError("Command {} failed with error code {}".format(cmd_desc, proc.returncode)) else: - logger.warn( - "Command %s had error code %s" - % (cmd_desc, proc.returncode)) + logger.warn("Command {} had error code {}".format(cmd_desc, proc.returncode)) + def filter_install_output(line): - if line.strip().startswith('running'): + if line.strip().startswith("running"): return Logger.INFO return Logger.DEBUG + def find_wheels(projects, search_dirs): """Find wheels from which we can import PROJECTS. @@ -838,22 +878,22 @@ def find_wheels(projects, search_dirs): for dirname in search_dirs: # This relies on only having "universal" wheels available. # The pattern could be tightened to require -py2.py3-none-any.whl. - files = glob.glob(os.path.join(dirname, project + '-*.whl')) + files = glob.glob(os.path.join(dirname, project + "-*.whl")) if files: wheels.append(os.path.abspath(files[0])) break else: # We're out of luck, so quit with a suitable error - logger.fatal('Cannot find a wheel for %s' % (project,)) + logger.fatal("Cannot find a wheel for {}".format(project)) return wheels -def install_wheel(project_names, py_executable, search_dirs=None, - download=False): + +def install_wheel(project_names, py_executable, search_dirs=None, download=False): if search_dirs is None: search_dirs = file_search_dirs() - wheels = find_wheels(['setuptools', 'pip'], search_dirs) + wheels = find_wheels(["setuptools", "pip"], search_dirs) pythonpath = os.pathsep.join(wheels) # PIP_FIND_LINKS uses space as the path separator and thus cannot have paths @@ -864,13 +904,16 @@ def install_wheel(project_names, py_executable, search_dirs=None, except ImportError: from urllib.parse import urljoin from urllib.request import pathname2url + def space_path2url(p): - if ' ' not in p: + if " " not in p: return p - return urljoin('file:', pathname2url(os.path.abspath(p))) - findlinks = ' '.join(space_path2url(d) for d in search_dirs) + return urljoin("file:", pathname2url(os.path.abspath(p))) + + findlinks = " ".join(space_path2url(d) for d in search_dirs) - SCRIPT = textwrap.dedent(""" + SCRIPT = textwrap.dedent( + """ import sys import pkgutil import tempfile @@ -900,10 +943,11 @@ def install_wheel(project_names, py_executable, search_dirs=None, finally: if cert_file is not None: os.remove(cert_file.name) - """).encode("utf8") + """ + ).encode("utf8") - cmd = [py_executable, '-'] + project_names - logger.start_progress('Installing %s...' % (', '.join(project_names))) + cmd = [py_executable, "-"] + project_names + logger.start_progress("Installing %s..." % (", ".join(project_names))) logger.indent += 2 env = { @@ -913,7 +957,7 @@ def install_wheel(project_names, py_executable, search_dirs=None, "PIP_USE_WHEEL": "1", "PIP_ONLY_BINARY": ":all:", "PIP_USER": "0", - "PIP_NO_INPUT": "1" + "PIP_NO_INPUT": "1", } if not download: @@ -926,10 +970,18 @@ def install_wheel(project_names, py_executable, search_dirs=None, logger.end_progress() -def create_environment(home_dir, site_packages=False, clear=False, - prompt=None, search_dirs=None, download=False, - no_setuptools=False, no_pip=False, no_wheel=False, - symlink=True): +def create_environment( + home_dir, + site_packages=False, + clear=False, + prompt=None, + search_dirs=None, + download=False, + no_setuptools=False, + no_pip=False, + no_wheel=False, + symlink=True, +): """ Creates a new environment in ``home_dir``. @@ -941,38 +993,35 @@ def create_environment(home_dir, site_packages=False, clear=False, """ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) - py_executable = os.path.abspath(install_python( - home_dir, lib_dir, inc_dir, bin_dir, - site_packages=site_packages, clear=clear, symlink=symlink)) + py_executable = os.path.abspath( + install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages=site_packages, clear=clear, symlink=symlink) + ) install_distutils(home_dir) to_install = [] if not no_setuptools: - to_install.append('setuptools') + to_install.append("setuptools") if not no_pip: - to_install.append('pip') + to_install.append("pip") if not no_wheel: - to_install.append('wheel') + to_install.append("wheel") if to_install: - install_wheel( - to_install, - py_executable, - search_dirs, - download=download, - ) + install_wheel(to_install, py_executable, search_dirs, download=download) install_activate(home_dir, bin_dir, prompt) install_python_config(home_dir, bin_dir, prompt) + def is_executable_file(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + def path_locations(home_dir): """Return the path locations for the environment (where libraries are, where scripts go, etc)""" @@ -984,10 +1033,11 @@ def path_locations(home_dir): # the name; this function will remove them (using the ~1 # format): mkdir(home_dir) - if ' ' in home_dir: + if " " in home_dir: import ctypes + GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW - size = max(len(home_dir)+1, 256) + size = max(len(home_dir) + 1, 256) buf = ctypes.create_unicode_buffer(size) try: u = unicode @@ -996,25 +1046,25 @@ def path_locations(home_dir): ret = GetShortPathName(u(home_dir), buf, size) if not ret: print('Error: the path "%s" has a space in it' % home_dir) - print('We could not determine the short pathname for it.') - print('Exiting.') + print("We could not determine the short pathname for it.") + print("Exiting.") sys.exit(3) home_dir = str(buf.value) - lib_dir = join(home_dir, 'Lib') - inc_dir = join(home_dir, 'Include') - bin_dir = join(home_dir, 'Scripts') + lib_dir = join(home_dir, "Lib") + inc_dir = join(home_dir, "Include") + bin_dir = join(home_dir, "Scripts") if is_jython: - lib_dir = join(home_dir, 'Lib') - inc_dir = join(home_dir, 'Include') - bin_dir = join(home_dir, 'bin') + lib_dir = join(home_dir, "Lib") + inc_dir = join(home_dir, "Include") + bin_dir = join(home_dir, "bin") elif is_pypy: lib_dir = home_dir - inc_dir = join(home_dir, 'include') - bin_dir = join(home_dir, 'bin') + inc_dir = join(home_dir, "include") + bin_dir = join(home_dir, "bin") elif not is_win: - lib_dir = join(home_dir, 'lib', py_version) - inc_dir = join(home_dir, 'include', py_version + abiflags) - bin_dir = join(home_dir, 'bin') + lib_dir = join(home_dir, "lib", py_version) + inc_dir = join(home_dir, "include", py_version + abiflags) + bin_dir = join(home_dir, "bin") return home_dir, lib_dir, inc_dir, bin_dir @@ -1022,18 +1072,21 @@ def change_prefix(filename, dst_prefix): prefixes = [sys.prefix] if is_darwin: - prefixes.extend(( - os.path.join("/Library/Python", sys.version[:3], "site-packages"), - os.path.join(sys.prefix, "Extras", "lib", "python"), - os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"), - # Python 2.6 no-frameworks - os.path.join("~", ".local", "lib","python", sys.version[:3], "site-packages"), - # System Python 2.7 on OSX Mountain Lion - os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages"))) - - if hasattr(sys, 'real_prefix'): + prefixes.extend( + ( + os.path.join("/Library/Python", sys.version[:3], "site-packages"), + os.path.join(sys.prefix, "Extras", "lib", "python"), + os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"), + # Python 2.6 no-frameworks + os.path.join("~", ".local", "lib", "python", sys.version[:3], "site-packages"), + # System Python 2.7 on OSX Mountain Lion + os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages"), + ) + ) + + if hasattr(sys, "real_prefix"): prefixes.append(sys.real_prefix) - if hasattr(sys, 'base_prefix'): + if hasattr(sys, "base_prefix"): prefixes.append(sys.base_prefix) prefixes = list(map(os.path.expanduser, prefixes)) prefixes = list(map(os.path.abspath, prefixes)) @@ -1041,20 +1094,20 @@ def change_prefix(filename, dst_prefix): prefixes = sorted(prefixes, key=len, reverse=True) filename = os.path.abspath(filename) # On Windows, make sure drive letter is uppercase - if is_win and filename[0] in 'abcdefghijklmnopqrstuvwxyz': + if is_win and filename[0] in "abcdefghijklmnopqrstuvwxyz": filename = filename[0].upper() + filename[1:] for i, prefix in enumerate(prefixes): - if is_win and prefix[0] in 'abcdefghijklmnopqrstuvwxyz': + if is_win and prefix[0] in "abcdefghijklmnopqrstuvwxyz": prefixes[i] = prefix[0].upper() + prefix[1:] for src_prefix in prefixes: if filename.startswith(src_prefix): _, relpath = filename.split(src_prefix, 1) - if src_prefix != os.sep: # sys.prefix == "/" + if src_prefix != os.sep: # sys.prefix == "/" assert relpath[0] == os.sep relpath = relpath[1:] return join(dst_prefix, relpath) - assert False, "Filename %s does not start with any of these prefixes: %s" % \ - (filename, prefixes) + assert False, "Filename {} does not start with any of these prefixes: {}".format(filename, prefixes) + def copy_required_modules(dst_prefix, symlink): import imp @@ -1071,10 +1124,13 @@ def copy_required_modules(dst_prefix, symlink): if f is not None: f.close() # special-case custom readline.so on OS X, but not for pypy: - if modname == 'readline' and sys.platform == 'darwin' and not ( - is_pypy or filename.endswith(join('lib-dynload', 'readline.so'))): - dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so') - elif modname == 'readline' and sys.platform == 'win32': + if ( + modname == "readline" + and sys.platform == "darwin" + and not (is_pypy or filename.endswith(join("lib-dynload", "readline.so"))) + ): + dst_filename = join(dst_prefix, "lib", "python%s" % sys.version[:3], "readline.so") + elif modname == "readline" and sys.platform == "win32": # special-case for Windows, where readline is not a # standard module, though it may have been installed in # site-packages by a third-party package @@ -1082,17 +1138,18 @@ def copy_required_modules(dst_prefix, symlink): else: dst_filename = change_prefix(filename, dst_prefix) copyfile(filename, dst_filename, symlink) - if filename.endswith('.pyc'): + if filename.endswith(".pyc"): pyfile = filename[:-1] if os.path.exists(pyfile): copyfile(pyfile, dst_filename[:-1], symlink) + def copy_tcltk(src, dest, symlink): """ copy tcl/tk libraries on Windows (issue #93) """ - for libversion in '8.5', '8.6': - for libname in 'tcl', 'tk': - srcdir = join(src, 'tcl', libname + libversion) - destdir = join(dest, 'tcl', libname + libversion) + for libversion in "8.5", "8.6": + for libname in "tcl", "tk": + srcdir = join(src, "tcl", libname + libversion) + destdir = join(dest, "tcl", libname + libversion) # Only copy the dirs from the above combinations that exist if os.path.exists(srcdir) and not os.path.exists(destdir): copyfileordir(srcdir, destdir, symlink) @@ -1103,7 +1160,7 @@ def subst_path(prefix_path, prefix, home_dir): prefix = os.path.normpath(prefix) home_dir = os.path.normpath(home_dir) if not prefix_path.startswith(prefix): - logger.warn('Path not in prefix %r %r', prefix_path, prefix) + logger.warn("Path not in prefix %r %r", prefix_path, prefix) return return prefix_path.replace(prefix, home_dir, 1) @@ -1111,20 +1168,20 @@ def subst_path(prefix_path, prefix, home_dir): def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, symlink=True): """Install just the base environment, no distutils patches etc""" if sys.executable.startswith(bin_dir): - print('Please use the *system* python to run this script') + print("Please use the *system* python to run this script") return if clear: rmtree(lib_dir) - ## FIXME: why not delete it? - ## Maybe it should delete everything with #!/path/to/venv/python in it - logger.notify('Not deleting %s', bin_dir) + # FIXME: why not delete it? + # Maybe it should delete everything with #!/path/to/venv/python in it + logger.notify("Not deleting %s", bin_dir) - if hasattr(sys, 'real_prefix'): - logger.notify('Using real prefix %r' % sys.real_prefix) + if hasattr(sys, "real_prefix"): + logger.notify("Using real prefix %r" % sys.real_prefix) prefix = sys.real_prefix - elif hasattr(sys, 'base_prefix'): - logger.notify('Using base prefix %r' % sys.base_prefix) + elif hasattr(sys, "base_prefix"): + logger.notify("Using base prefix %r" % sys.base_prefix) prefix = sys.base_prefix else: prefix = sys.prefix @@ -1132,13 +1189,13 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy fix_lib64(lib_dir, symlink) stdlib_dirs = [os.path.dirname(os.__file__)] if is_win: - stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs')) + stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), "DLLs")) elif is_darwin: - stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages')) - if hasattr(os, 'symlink'): - logger.info('Symlinking Python bootstrap modules') + stdlib_dirs.append(join(stdlib_dirs[0], "site-packages")) + if hasattr(os, "symlink"): + logger.info("Symlinking Python bootstrap modules") else: - logger.info('Copying Python bootstrap modules') + logger.info("Copying Python bootstrap modules") logger.indent += 2 try: # copy required files... @@ -1147,7 +1204,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy continue for fn in os.listdir(stdlib_dir): bn = os.path.splitext(fn)[0] - if fn != 'site-packages' and bn in REQUIRED_FILES: + if fn != "site-packages" and bn in REQUIRED_FILES: copyfile(join(stdlib_dir, fn), join(lib_dir, fn), symlink) # ...and modules copy_required_modules(home_dir, symlink) @@ -1156,34 +1213,34 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy # ...copy tcl/tk if is_win: copy_tcltk(prefix, home_dir, symlink) - mkdir(join(lib_dir, 'site-packages')) + mkdir(join(lib_dir, "site-packages")) import site + site_filename = site.__file__ - if site_filename.endswith('.pyc') or site_filename.endswith('.pyo'): + if site_filename.endswith(".pyc") or site_filename.endswith(".pyo"): site_filename = site_filename[:-1] - elif site_filename.endswith('$py.class'): - site_filename = site_filename.replace('$py.class', '.py') + elif site_filename.endswith("$py.class"): + site_filename = site_filename.replace("$py.class", ".py") site_filename_dst = change_prefix(site_filename, home_dir) site_dir = os.path.dirname(site_filename_dst) writefile(site_filename_dst, SITE_PY) - writefile(join(site_dir, 'orig-prefix.txt'), prefix) - site_packages_filename = join(site_dir, 'no-global-site-packages.txt') + writefile(join(site_dir, "orig-prefix.txt"), prefix) + site_packages_filename = join(site_dir, "no-global-site-packages.txt") if not site_packages: - writefile(site_packages_filename, '') + writefile(site_packages_filename, "") if is_pypy or is_win: - stdinc_dir = join(prefix, 'include') + stdinc_dir = join(prefix, "include") else: - stdinc_dir = join(prefix, 'include', py_version + abiflags) + stdinc_dir = join(prefix, "include", py_version + abiflags) if os.path.exists(stdinc_dir): copyfile(stdinc_dir, inc_dir, symlink) else: - logger.debug('No include dir %s' % stdinc_dir) + logger.debug("No include dir %s" % stdinc_dir) platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1) if platinc_dir != stdinc_dir: - platinc_dest = distutils.sysconfig.get_python_inc( - plat_specific=1, prefix=home_dir) + platinc_dest = distutils.sysconfig.get_python_inc(plat_specific=1, prefix=home_dir) if platinc_dir == platinc_dest: # Do platinc_dest manually due to a CPython bug; # not http://bugs.python.org/issue3386 but a close cousin @@ -1198,92 +1255,82 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy # pypy never uses exec_prefix, just ignore it if sys.exec_prefix != prefix and not is_pypy: if is_win: - exec_dir = join(sys.exec_prefix, 'lib') + exec_dir = join(sys.exec_prefix, "lib") elif is_jython: - exec_dir = join(sys.exec_prefix, 'Lib') + exec_dir = join(sys.exec_prefix, "Lib") else: - exec_dir = join(sys.exec_prefix, 'lib', py_version) + exec_dir = join(sys.exec_prefix, "lib", py_version) for fn in os.listdir(exec_dir): copyfile(join(exec_dir, fn), join(lib_dir, fn), symlink) if is_jython: # Jython has either jython-dev.jar and javalib/ dir, or just # jython.jar - for name in 'jython-dev.jar', 'javalib', 'jython.jar': + for name in "jython-dev.jar", "javalib", "jython.jar": src = join(prefix, name) if os.path.exists(src): copyfile(src, join(home_dir, name), symlink) # XXX: registry should always exist after Jython 2.5rc1 - src = join(prefix, 'registry') + src = join(prefix, "registry") if os.path.exists(src): - copyfile(src, join(home_dir, 'registry'), symlink=False) - copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'), - symlink=False) + copyfile(src, join(home_dir, "registry"), symlink=False) + copyfile(join(prefix, "cachedir"), join(home_dir, "cachedir"), symlink=False) mkdir(bin_dir) py_executable = join(bin_dir, os.path.basename(sys.executable)) - if 'Python.framework' in prefix: + if "Python.framework" in prefix: # OS X framework builds cause validation to break # https://github.com/pypa/virtualenv/issues/322 - if os.environ.get('__PYVENV_LAUNCHER__'): + if os.environ.get("__PYVENV_LAUNCHER__"): del os.environ["__PYVENV_LAUNCHER__"] - if re.search(r'/Python(?:-32|-64)*$', py_executable): + if re.search(r"/Python(?:-32|-64)*$", py_executable): # The name of the python executable is not quite what # we want, rename it. - py_executable = os.path.join( - os.path.dirname(py_executable), 'python') + py_executable = os.path.join(os.path.dirname(py_executable), "python") - logger.notify('New %s executable in %s', expected_exe, py_executable) + logger.notify("New %s executable in %s", expected_exe, py_executable) pcbuild_dir = os.path.dirname(sys.executable) - pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth') - if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')): - logger.notify('Detected python running from build directory %s', pcbuild_dir) - logger.notify('Writing .pth file linking to build directory for *.pyd files') + pyd_pth = os.path.join(lib_dir, "site-packages", "virtualenv_builddir_pyd.pth") + if is_win and os.path.exists(os.path.join(pcbuild_dir, "build.bat")): + logger.notify("Detected python running from build directory %s", pcbuild_dir) + logger.notify("Writing .pth file linking to build directory for *.pyd files") writefile(pyd_pth, pcbuild_dir) else: pcbuild_dir = None if os.path.exists(pyd_pth): - logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth) + logger.info("Deleting %s (not Windows env or not build directory python)" % pyd_pth) os.unlink(pyd_pth) if sys.executable != py_executable: - ## FIXME: could I just hard link? + # FIXME: could I just hard link? executable = sys.executable shutil.copyfile(executable, py_executable) make_exe(py_executable) if is_win or is_cygwin: - pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe') + pythonw = os.path.join(os.path.dirname(sys.executable), "pythonw.exe") if os.path.exists(pythonw): - logger.info('Also created pythonw.exe') - shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe')) - python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe') - python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe') + logger.info("Also created pythonw.exe") + shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), "pythonw.exe")) + python_d = os.path.join(os.path.dirname(sys.executable), "python_d.exe") + python_d_dest = os.path.join(os.path.dirname(py_executable), "python_d.exe") if os.path.exists(python_d): - logger.info('Also created python_d.exe') + logger.info("Also created python_d.exe") shutil.copyfile(python_d, python_d_dest) elif os.path.exists(python_d_dest): - logger.info('Removed python_d.exe as it is no longer at the source') + logger.info("Removed python_d.exe as it is no longer at the source") os.unlink(python_d_dest) # we need to copy the DLL to enforce that windows will load the correct one. # may not exist if we are cygwin. if is_pypy: - py_executable_dlls = [ - ( - 'libpypy-c.dll', - 'libpypy_d-c.dll', - ), - ] + py_executable_dlls = [("libpypy-c.dll", "libpypy_d-c.dll")] else: py_executable_dlls = [ + ("python%s.dll" % (sys.version_info[0]), "python%s_d.dll" % (sys.version_info[0])), ( - 'python%s.dll' % (sys.version_info[0]), - 'python%s_d.dll' % (sys.version_info[0]) + "python{}{}.dll".format(sys.version_info[0], sys.version_info[1]), + "python{}{}_d.dll".format(sys.version_info[0], sys.version_info[1]), ), - ( - 'python%s%s.dll' % (sys.version_info[0], sys.version_info[1]), - 'python%s%s_d.dll' % (sys.version_info[0], sys.version_info[1]) - ) ] for py_executable_dll, py_executable_dll_d in py_executable_dlls: @@ -1291,108 +1338,102 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d) pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d) if os.path.exists(pythondll): - logger.info('Also created %s' % py_executable_dll) + logger.info("Also created %s" % py_executable_dll) shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll)) if os.path.exists(pythondll_d): - logger.info('Also created %s' % py_executable_dll_d) + logger.info("Also created %s" % py_executable_dll_d) shutil.copyfile(pythondll_d, pythondll_d_dest) elif os.path.exists(pythondll_d_dest): - logger.info('Removed %s as the source does not exist' % pythondll_d_dest) + logger.info("Removed %s as the source does not exist" % pythondll_d_dest) os.unlink(pythondll_d_dest) if is_pypy: # make a symlink python --> pypy-c - python_executable = os.path.join(os.path.dirname(py_executable), 'python') - if sys.platform in ('win32', 'cygwin'): - python_executable += '.exe' - logger.info('Also created executable %s' % python_executable) + python_executable = os.path.join(os.path.dirname(py_executable), "python") + if sys.platform in ("win32", "cygwin"): + python_executable += ".exe" + logger.info("Also created executable %s" % python_executable) copyfile(py_executable, python_executable, symlink) if is_win: - for name in ['libexpat.dll', - 'libeay32.dll', 'ssleay32.dll', 'sqlite3.dll', - 'tcl85.dll', 'tk85.dll']: + for name in ["libexpat.dll", "libeay32.dll", "ssleay32.dll", "sqlite3.dll", "tcl85.dll", "tk85.dll"]: src = join(prefix, name) if os.path.exists(src): copyfile(src, join(bin_dir, name), symlink) for d in sys.path: - if d.endswith('lib_pypy'): + if d.endswith("lib_pypy"): break else: - logger.fatal('Could not find lib_pypy in sys.path') + logger.fatal("Could not find lib_pypy in sys.path") raise SystemExit(3) - logger.info('Copying lib_pypy') - copyfile(d, os.path.join(home_dir, 'lib_pypy'), symlink) + logger.info("Copying lib_pypy") + copyfile(d, os.path.join(home_dir, "lib_pypy"), symlink) if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe: - secondary_exe = os.path.join(os.path.dirname(py_executable), - expected_exe) + secondary_exe = os.path.join(os.path.dirname(py_executable), expected_exe) py_executable_ext = os.path.splitext(py_executable)[1] - if py_executable_ext.lower() == '.exe': + if py_executable_ext.lower() == ".exe": # python2.4 gives an extension of '.4' :P secondary_exe += py_executable_ext if os.path.exists(secondary_exe): - logger.warn('Not overwriting existing %s script %s (you must use %s)' - % (expected_exe, secondary_exe, py_executable)) + logger.warn( + "Not overwriting existing {} script {} (you must use {})".format( + expected_exe, secondary_exe, py_executable + ) + ) else: - logger.notify('Also creating executable in %s' % secondary_exe) + logger.notify("Also creating executable in %s" % secondary_exe) shutil.copyfile(sys.executable, secondary_exe) make_exe(secondary_exe) - if '.framework' in prefix: - if 'Python.framework' in prefix: - logger.debug('MacOSX Python framework detected') + if ".framework" in prefix: + if "Python.framework" in prefix: + logger.debug("MacOSX Python framework detected") # Make sure we use the embedded interpreter inside # the framework, even if sys.executable points to # the stub executable in ${sys.prefix}/bin # See http://groups.google.com/group/python-virtualenv/ # browse_thread/thread/17cab2f85da75951 - original_python = os.path.join( - prefix, 'Resources/Python.app/Contents/MacOS/Python') - if 'EPD' in prefix: - logger.debug('EPD framework detected') - original_python = os.path.join(prefix, 'bin/python') + original_python = os.path.join(prefix, "Resources/Python.app/Contents/MacOS/Python") + if "EPD" in prefix: + logger.debug("EPD framework detected") + original_python = os.path.join(prefix, "bin/python") shutil.copy(original_python, py_executable) # Copy the framework's dylib into the virtual # environment - virtual_lib = os.path.join(home_dir, '.Python') + virtual_lib = os.path.join(home_dir, ".Python") if os.path.exists(virtual_lib): os.unlink(virtual_lib) - copyfile( - os.path.join(prefix, 'Python'), - virtual_lib, - symlink) + copyfile(os.path.join(prefix, "Python"), virtual_lib, symlink) # And then change the install_name of the copied python executable try: - mach_o_change(py_executable, - os.path.join(prefix, 'Python'), - '@executable_path/../.Python') - except: + mach_o_change(py_executable, os.path.join(prefix, "Python"), "@executable_path/../.Python") + except Exception: e = sys.exc_info()[1] - logger.warn("Could not call mach_o_change: %s. " - "Trying to call install_name_tool instead." % e) + logger.warn("Could not call mach_o_change: %s. " "Trying to call install_name_tool instead." % e) try: call_subprocess( - ["install_name_tool", "-change", - os.path.join(prefix, 'Python'), - '@executable_path/../.Python', - py_executable]) - except: - logger.fatal("Could not call install_name_tool -- you must " - "have Apple's development tools installed") + [ + "install_name_tool", + "-change", + os.path.join(prefix, "Python"), + "@executable_path/../.Python", + py_executable, + ] + ) + except Exception: + logger.fatal("Could not call install_name_tool -- you must " "have Apple's development tools installed") raise if not is_win: # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist - 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]) - py_exe_no_version = 'python' - required_symlinks = [ py_exe_no_version, py_exe_version_major, - py_exe_version_major_minor ] + 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]) + py_exe_no_version = "python" + required_symlinks = [py_exe_no_version, py_exe_version_major, py_exe_version_major_minor] py_executable_base = os.path.basename(py_executable) @@ -1409,17 +1450,19 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy else: copyfile(py_executable, full_pth, symlink) - cmd = [py_executable, '-c', 'import sys;out=sys.stdout;' - 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))'] + cmd = [ + py_executable, + "-c", + "import sys;out=sys.stdout;" 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))', + ] logger.info('Testing executable with %s %s "%s"' % tuple(cmd)) try: - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) proc_stdout, proc_stderr = proc.communicate() except OSError: e = sys.exc_info()[1] if e.errno == errno.EACCES: - logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e)) + logger.fatal("ERROR: The executable {} could not be run: {}".format(py_executable, e)) sys.exit(100) else: raise e @@ -1427,105 +1470,102 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy proc_stdout = proc_stdout.strip().decode("utf-8") proc_stdout = os.path.normcase(os.path.abspath(proc_stdout)) norm_home_dir = os.path.normcase(os.path.abspath(home_dir)) - if hasattr(norm_home_dir, 'decode'): + if hasattr(norm_home_dir, "decode"): norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding()) if proc_stdout != norm_home_dir: - logger.fatal( - 'ERROR: The executable %s is not functioning' % py_executable) - logger.fatal( - 'ERROR: It thinks sys.prefix is %r (should be %r)' - % (proc_stdout, norm_home_dir)) - logger.fatal( - 'ERROR: virtualenv is not compatible with this system or executable') + logger.fatal("ERROR: The executable %s is not functioning" % py_executable) + logger.fatal("ERROR: It thinks sys.prefix is {!r} (should be {!r})".format(proc_stdout, norm_home_dir)) + logger.fatal("ERROR: virtualenv is not compatible with this system or executable") if is_win: logger.fatal( - 'Note: some Windows users have reported this error when they ' + "Note: some Windows users have reported this error when they " 'installed Python for "Only this user" or have multiple ' - 'versions of Python installed. Copying the appropriate ' - 'PythonXX.dll to the virtualenv Scripts/ directory may fix ' - 'this problem.') + "versions of Python installed. Copying the appropriate " + "PythonXX.dll to the virtualenv Scripts/ directory may fix " + "this problem." + ) sys.exit(100) else: - logger.info('Got sys.prefix result: %r' % proc_stdout) + logger.info("Got sys.prefix result: %r" % proc_stdout) - pydistutils = os.path.expanduser('~/.pydistutils.cfg') + pydistutils = os.path.expanduser("~/.pydistutils.cfg") if os.path.exists(pydistutils): - logger.notify('Please make sure you remove any previous custom paths from ' - 'your %s file.' % pydistutils) - ## FIXME: really this should be calculated earlier + logger.notify("Please make sure you remove any previous custom paths from " "your %s file." % pydistutils) + # FIXME: really this should be calculated earlier fix_local_scheme(home_dir, symlink) if site_packages: if os.path.exists(site_packages_filename): - logger.info('Deleting %s' % site_packages_filename) + logger.info("Deleting %s" % site_packages_filename) os.unlink(site_packages_filename) return py_executable def install_activate(home_dir, bin_dir, prompt=None): - if is_win or is_jython and os._name == 'nt': - files = { - 'activate.bat': ACTIVATE_BAT, - 'deactivate.bat': DEACTIVATE_BAT, - 'activate.ps1': ACTIVATE_PS, - } + if is_win or is_jython and os._name == "nt": + files = {"activate.bat": ACTIVATE_BAT, "deactivate.bat": DEACTIVATE_BAT, "activate.ps1": ACTIVATE_PS} # MSYS needs paths of the form /c/path/to/file - drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/')) + drive, tail = os.path.splitdrive(home_dir.replace(os.sep, "/")) home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail) # Run-time conditional enables (basic) Cygwin compatibility - home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" % - (home_dir, home_dir_msys)) - files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh) + home_dir_sh = """$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '{}'; else echo '{}'; fi;)""".format( + home_dir, home_dir_msys + ) + files["activate"] = ACTIVATE_SH.replace("__VIRTUAL_ENV__", home_dir_sh) else: - files = {'activate': ACTIVATE_SH} + files = {"activate": ACTIVATE_SH} # suppling activate.fish in addition to, not instead of, the # bash script support. - files['activate.fish'] = ACTIVATE_FISH + files["activate.fish"] = ACTIVATE_FISH # same for csh/tcsh support... - files['activate.csh'] = ACTIVATE_CSH + files["activate.csh"] = ACTIVATE_CSH - files['activate_this.py'] = ACTIVATE_THIS + files["activate_this.py"] = ACTIVATE_THIS install_files(home_dir, bin_dir, prompt, files) + def install_files(home_dir, bin_dir, prompt, files): - if hasattr(home_dir, 'decode'): + if hasattr(home_dir, "decode"): home_dir = home_dir.decode(sys.getfilesystemencoding()) vname = os.path.basename(home_dir) for name, content in files.items(): - content = content.replace('__VIRTUAL_PROMPT__', prompt or '') - content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname) - content = content.replace('__VIRTUAL_ENV__', home_dir) - content = content.replace('__VIRTUAL_NAME__', vname) - content = content.replace('__BIN_NAME__', os.path.basename(bin_dir)) + content = content.replace("__VIRTUAL_PROMPT__", prompt or "") + content = content.replace("__VIRTUAL_WINPROMPT__", prompt or "(%s)" % vname) + content = content.replace("__VIRTUAL_ENV__", home_dir) + content = content.replace("__VIRTUAL_NAME__", vname) + content = content.replace("__BIN_NAME__", os.path.basename(bin_dir)) writefile(os.path.join(bin_dir, name), content) + def install_python_config(home_dir, bin_dir, prompt=None): - if sys.platform == 'win32' or is_jython and os._name == 'nt': + if sys.platform == "win32" or is_jython and os._name == "nt": files = {} else: - files = {'python-config': PYTHON_CONFIG} + files = {"python-config": PYTHON_CONFIG} install_files(home_dir, bin_dir, prompt, files) - for name, content in files.items(): + for name, _ in files.items(): make_exe(os.path.join(bin_dir, name)) + def install_distutils(home_dir): distutils_path = change_prefix(distutils.__path__[0], home_dir) mkdir(distutils_path) - ## FIXME: maybe this prefix setting should only be put in place if - ## there's a local distutils.cfg with a prefix setting? + # FIXME: maybe this prefix setting should only be put in place if + # there's a local distutils.cfg with a prefix setting? home_dir = os.path.abspath(home_dir) - ## FIXME: this is breaking things, removing for now: - #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir - writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT) - writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False) + # FIXME: this is breaking things, removing for now: + # distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir + writefile(os.path.join(distutils_path, "__init__.py"), DISTUTILS_INIT) + writefile(os.path.join(distutils_path, "distutils.cfg"), DISTUTILS_CFG, overwrite=False) + def fix_local_scheme(home_dir, symlink=True): """ @@ -1537,15 +1577,19 @@ def fix_local_scheme(home_dir, symlink=True): except ImportError: pass else: - if sysconfig._get_default_scheme() == 'posix_local': - local_path = os.path.join(home_dir, 'local') + if sysconfig._get_default_scheme() == "posix_local": + local_path = os.path.join(home_dir, "local") if not os.path.exists(local_path): os.mkdir(local_path) for subdir_name in os.listdir(home_dir): - if subdir_name == 'local': + if subdir_name == "local": continue - copyfile(os.path.abspath(os.path.join(home_dir, subdir_name)), \ - os.path.join(local_path, subdir_name), symlink) + copyfile( + os.path.abspath(os.path.join(home_dir, subdir_name)), + os.path.join(local_path, subdir_name), + symlink, + ) + def fix_lib64(lib_dir, symlink=True): """ @@ -1556,29 +1600,27 @@ def fix_lib64(lib_dir, symlink=True): # PyPy's library path scheme is not affected by this. # Return early or we will die on the following assert. if is_pypy: - logger.debug('PyPy detected, skipping lib64 symlinking') + logger.debug("PyPy detected, skipping lib64 symlinking") return # Check we have a lib64 library path - if not [p for p in distutils.sysconfig.get_config_vars().values() - if isinstance(p, basestring) and 'lib64' in p]: + if not [p for p in distutils.sysconfig.get_config_vars().values() if isinstance(p, basestring) and "lib64" in p]: return - logger.debug('This system uses lib64; symlinking lib64 to lib') + logger.debug("This system uses lib64; symlinking lib64 to lib") - assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], ( - "Unexpected python lib dir: %r" % lib_dir) + assert os.path.basename(lib_dir) == "python%s" % sys.version[:3], "Unexpected python lib dir: %r" % lib_dir lib_parent = os.path.dirname(lib_dir) top_level = os.path.dirname(lib_parent) - lib_dir = os.path.join(top_level, 'lib') - lib64_link = os.path.join(top_level, 'lib64') - assert os.path.basename(lib_parent) == 'lib', ( - "Unexpected parent dir: %r" % lib_parent) + lib_dir = os.path.join(top_level, "lib") + lib64_link = os.path.join(top_level, "lib64") + assert os.path.basename(lib_parent) == "lib", "Unexpected parent dir: %r" % lib_parent if os.path.lexists(lib64_link): return if symlink: - os.symlink('lib', lib64_link) + os.symlink("lib", lib64_link) else: - copyfile('lib', lib64_link) + copyfile("lib", lib64_link) + def resolve_interpreter(exe): """ @@ -1594,52 +1636,58 @@ def resolve_interpreter(exe): if os.path.abspath(exe) != exe: exe = distutils.spawn.find_executable(exe) or exe if not os.path.exists(exe): - logger.fatal('The path %s (from --python=%s) does not exist' % (exe, orig_exe)) + logger.fatal("The path {} (from --python={}) does not exist".format(exe, orig_exe)) raise SystemExit(3) if not is_executable(exe): - logger.fatal('The path %s (from --python=%s) is not an executable file' % (exe, orig_exe)) + logger.fatal("The path {} (from --python={}) is not an executable file".format(exe, orig_exe)) raise SystemExit(3) return exe + def is_executable(exe): """Checks a file is executable""" return os.path.isfile(exe) and os.access(exe, os.X_OK) -############################################################ -## Relocating the environment: +# Relocating the environment: def make_environment_relocatable(home_dir): """ Makes the already-existing environment use relative paths, and takes out the #!-based environment selection in scripts. """ home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) - activate_this = os.path.join(bin_dir, 'activate_this.py') + activate_this = os.path.join(bin_dir, "activate_this.py") if not os.path.exists(activate_this): logger.fatal( - 'The environment doesn\'t have a file %s -- please re-run virtualenv ' - 'on this environment to update it' % activate_this) + "The environment doesn't have a file %s -- please re-run virtualenv " + "on this environment to update it" % activate_this + ) fixup_scripts(home_dir, bin_dir) fixup_pth_and_egg_link(home_dir) - ## FIXME: need to fix up distutils.cfg + # FIXME: need to fix up distutils.cfg + + +OK_ABS_SCRIPTS = [ + "python", + "python%s" % sys.version[:3], + "activate", + "activate.bat", + "activate_this.py", + "activate.fish", + "activate.csh", +] -OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3], - 'activate', 'activate.bat', 'activate_this.py', - 'activate.fish', 'activate.csh'] def fixup_scripts(home_dir, bin_dir): if is_win: - new_shebang_args = ( - '%s /c' % os.path.normcase(os.environ.get('COMSPEC', 'cmd.exe')), - '', '.exe') + new_shebang_args = ("%s /c" % os.path.normcase(os.environ.get("COMSPEC", "cmd.exe")), "", ".exe") else: - new_shebang_args = ('/usr/bin/env', sys.version[:3], '') + new_shebang_args = ("/usr/bin/env", sys.version[:3], "") # This is what we expect at the top of scripts: - shebang = '#!%s' % os.path.normcase(os.path.join( - os.path.abspath(bin_dir), 'python%s' % new_shebang_args[2])) + shebang = "#!%s" % os.path.normcase(os.path.join(os.path.abspath(bin_dir), "python%s" % new_shebang_args[2])) # This is what we'll put: - new_shebang = '#!%s python%s%s' % new_shebang_args + new_shebang = "#!%s python%s%s" % new_shebang_args for filename in os.listdir(bin_dir): filename = os.path.join(bin_dir, filename) @@ -1647,15 +1695,15 @@ def fixup_scripts(home_dir, bin_dir): # ignore subdirs, e.g. .svn ones. continue lines = None - with open(filename, 'rb') as f: + with open(filename, "rb") as f: try: - lines = f.read().decode('utf-8').splitlines() + lines = f.read().decode("utf-8").splitlines() except UnicodeDecodeError: # This is probably a binary program instead # of a script, so just ignore it. continue if not lines: - logger.warn('Script %s is an empty file' % filename) + logger.warn("Script %s is an empty file" % filename) continue old_shebang = lines[0].strip() @@ -1663,33 +1711,41 @@ def fixup_scripts(home_dir, bin_dir): if not old_shebang.startswith(shebang): if os.path.basename(filename) in OK_ABS_SCRIPTS: - logger.debug('Cannot make script %s relative' % filename) + logger.debug("Cannot make script %s relative" % filename) elif lines[0].strip() == new_shebang: - logger.info('Script %s has already been made relative' % filename) + logger.info("Script %s has already been made relative" % filename) else: - logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)' - % (filename, shebang)) + logger.warn( + "Script %s cannot be made relative (it's not a normal script that starts with %s)" + % (filename, shebang) + ) continue - logger.notify('Making script %s relative' % filename) + logger.notify("Making script %s relative" % filename) script = relative_script([new_shebang] + lines[1:]) - with open(filename, 'wb') as f: - f.write('\n'.join(script).encode('utf-8')) + with open(filename, "wb") as f: + f.write("\n".join(script).encode("utf-8")) def relative_script(lines): "Return a script that'll work in a relocatable environment." - activate = "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" + activate = ( + "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" + ) # Find the last future statement in the script. If we insert the activation # line before a future statement, Python will raise a SyntaxError. activate_at = None for idx, line in reversed(list(enumerate(lines))): - if line.split()[:3] == ['from', '__future__', 'import']: + if line.split()[:3] == ["from", "__future__", "import"]: activate_at = idx + 1 break if activate_at is None: # Activate after the shebang. activate_at = 1 - return lines[:activate_at] + ['', activate, ''] + lines[activate_at:] + return lines[:activate_at] + ["", activate, ""] + lines[activate_at:] + def fixup_pth_and_egg_link(home_dir, sys_path=None): """Makes .pth and .egg-link files use relative paths""" @@ -1698,26 +1754,27 @@ def fixup_pth_and_egg_link(home_dir, sys_path=None): sys_path = sys.path for path in sys_path: if not path: - path = '.' + path = "." if not os.path.isdir(path): continue path = os.path.normcase(os.path.abspath(path)) if not path.startswith(home_dir): - logger.debug('Skipping system (non-environment) directory %s' % path) + logger.debug("Skipping system (non-environment) directory %s" % path) continue for filename in os.listdir(path): filename = os.path.join(path, filename) - if filename.endswith('.pth'): + if filename.endswith(".pth"): if not os.access(filename, os.W_OK): - logger.warn('Cannot write .pth file %s, skipping' % filename) + logger.warn("Cannot write .pth file %s, skipping" % filename) else: fixup_pth_file(filename) - if filename.endswith('.egg-link'): + if filename.endswith(".egg-link"): if not os.access(filename, os.W_OK): - logger.warn('Cannot write .egg-link file %s, skipping' % filename) + logger.warn("Cannot write .egg-link file %s, skipping" % filename) else: fixup_egg_link(filename) + def fixup_pth_file(filename): lines = [] prev_lines = [] @@ -1725,32 +1782,33 @@ def fixup_pth_file(filename): prev_lines = f.readlines() for line in prev_lines: line = line.strip() - if (not line or line.startswith('#') or line.startswith('import ') - or os.path.abspath(line) != line): + if not line or line.startswith("#") or line.startswith("import ") or os.path.abspath(line) != line: lines.append(line) else: new_value = make_relative_path(filename, line) if line != new_value: - logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename)) + logger.debug("Rewriting path {} as {} (in {})".format(line, new_value, filename)) lines.append(new_value) if lines == prev_lines: - logger.info('No changes to .pth file %s' % filename) + logger.info("No changes to .pth file %s" % filename) return - logger.notify('Making paths in .pth file %s relative' % filename) - with open(filename, 'w') as f: - f.write('\n'.join(lines) + '\n') + logger.notify("Making paths in .pth file %s relative" % filename) + with open(filename, "w") as f: + f.write("\n".join(lines) + "\n") + def fixup_egg_link(filename): with open(filename) as f: link = f.readline().strip() if os.path.abspath(link) != link: - logger.debug('Link in %s already relative' % filename) + logger.debug("Link in %s already relative" % filename) return new_link = make_relative_path(filename, link) - logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link)) - with open(filename, 'w') as f: + logger.notify("Rewriting link {} in {} as {}".format(link, filename, new_link)) + with open(filename, "w") as f: f.write(new_link) + def make_relative_path(source, dest, dest_is_directory=True): """ Make a filename relative, where the filename is dest, and it is @@ -1776,20 +1834,17 @@ def make_relative_path(source, dest, dest_is_directory=True): while dest_parts and source_parts and dest_parts[0] == source_parts[0]: dest_parts.pop(0) source_parts.pop(0) - full_parts = ['..']*len(source_parts) + dest_parts + full_parts = [".."] * len(source_parts) + dest_parts if not dest_is_directory: full_parts.append(dest_filename) if not full_parts: # Special case for the current directory (otherwise it'd be '') - return './' + return "./" return os.path.sep.join(full_parts) - -############################################################ -## Bootstrap script creation: - -def create_bootstrap_script(extra_text, python_version=''): +# Bootstrap script creation: +def create_bootstrap_script(extra_text, python_version=""): """ Creates a bootstrap script, which is like this script but with extend_parser, adjust_options, and after_install hooks. @@ -1830,169 +1885,169 @@ def create_bootstrap_script(extra_text, python_version=''): be run with a particular Python version. """ filename = __file__ - if filename.endswith('.pyc'): + if filename.endswith(".pyc"): filename = filename[:-1] - with codecs.open(filename, 'r', encoding='utf-8') as f: + with codecs.open(filename, "r", encoding="utf-8") as f: content = f.read() - py_exe = 'python%s' % python_version - content = (('#!/usr/bin/env %s\n' % py_exe) - + '## WARNING: This file is generated\n' - + content) - return content.replace('##EXT' 'END##', extra_text) + py_exe = "python%s" % python_version + content = ("#!/usr/bin/env %s\n" % py_exe) + "# WARNING: This file is generated\n" + content + return content.replace("##EXT" "END##", extra_text) -##EXTEND## +# EXTEND def convert(s): - b = base64.b64decode(s.encode('ascii')) - return zlib.decompress(b).decode('utf-8') - -##file site.py -SITE_PY = convert(""" -eJzFPf1z2zaWv/OvwMqToZTKdOJ0e3tO3RsncVrfuYm3yc7m1vXoKAmyWFMkS5C2tTd3f/u9DwAE -+CHb2+6cphNLJPDw8PC+8PAeOhqNTopCZkuxyZd1KoWScblYiyKu1kqs8lJU66Rc7hdxWW3h6eIm -vpZKVLlQWxVhqygInv/GT/BcfF4nyqAA3+K6yjdxlSziNN2KZFPkZSWXYlmXSXYtkiypkjhN/g4t -8iwSz387BsFZJmDmaSJLcStLBXCVyFfiYlut80yM6wLn/DL6Y/xqMhVqUSZFBQ1KjTNQZB1XQSbl -EtCElrUCUiaV3FeFXCSrZGEb3uV1uhRFGi+k+K//4qlR0zAMVL6Rd2tZSpEBMgBTAqwC8YCvSSkW -+VJGQryRixgH4OcNsQKGNsU1U0jGLBdpnl3DnDK5kErF5VaM53VFgAhlscwBpwQwqJI0De7y8kZN -YElpPe7gkYiZPfzJMHvAPHH8LucAjh+z4C9Zcj9l2MA9CK5aM9uUcpXcixjBwk95Lxcz/WycrMQy -Wa2ABlk1wSYBI6BEmswPClqOb/UKfXdAWFmujGEMiShzY35JPaLgrBJxqoBt6wJppAjzd3KexBlQ -I7uF4QAikDToG2eZqMqOQ7MTOQAocR0rkJKNEuNNnGTArD/GC0L7r0m2zO/UhCgAq6XEL7Wq3PmP -ewgArR0CTANcLLOadZYmNzLdTgCBz4B9KVWdVigQy6SUiyovE6kIAKC2FfIekJ6KuJSahMyZRm6n -RH+iSZLhwqKAocDjSyTJKrmuS5IwsUqAc4Er3n/8Sbw7fXN28kHzmAHGMnu9AZwBCi20gxMMIA5q -VR6kOQh0FJzjHxEvlyhk1zg+4NU0OHhwpYMxzL2I2n2cBQey68XVw8AcK1AmNFZA/f4bukzVGujz -Pw+sdxCcDFGFJs7f7tY5yGQWb6RYx8xfyBnBtxrOd1FRrV8DNyiEUwGpFC4OIpggPCCJS7NxnklR -AIulSSYnAVBoTm39VQRW+JBn+7TWLU4ACGWQwUvn2YRGzCRMtAvrNeoL03hLM9NNArvOm7wkxQH8 -ny1IF6VxdkM4KmIo/jaX10mWIULIC0G4F9LA6iYBTlxG4pxakV4wjUTI2otbokjUwEvIdMCT8j7e -FKmcsviibt2tRmgwWQmz1ilzHLSsSL3SqjVT7eW9w+hLi+sIzWpdSgBezz2hW+X5VMxBZxM2Rbxh -8arucuKcoEeeqBPyBLWEvvgdKHqiVL2R9iXyCmgWYqhgladpfgckOwoCIfawkTHKPnPCW3gH/wJc -/DeV1WIdBM5IFrAGhcgPgUIgYBJkprlaI+Fxm2bltpJJMtYUebmUJQ31OGIfMOKPbIxzDT7klTZq -PF1c5XyTVKiS5tpkJmzxsrBi/fia5w3TAMutiGamaUOnDU4vLdbxXBqXZC5XKAl6kV7bZYcxg54x -yRZXYsNWBt4BWWTCFqRfsaDSWVWSnACAwcIXZ0lRp9RIIYOJGAbaFAR/E6NJz7WzBOzNZjlAhcTm -ewH2B3D7O4jR3ToB+iwAAmgY1FKwfPOkKtFBaPRR4Bt905/HB049W2nbxEOu4iTVVj7OgjN6eFqW -JL4LWWCvqSaGghlmFbp21xnQEcV8NBoFgXGHtsp8zVVQldsjYAVhxpnN5nWChm82Q1Ovf6iARxHO -wF43287CAw1hOn0AKjldVmW+wdd2bp9AmcBY2CPYExekZSQ7yB4nvkbyuSq9ME3RdjvsLFAPBRc/ -nb4/+3L6SRyLy0alTdv67ArGPM1iYGuyCMBUrWEbXQYtUfElqPvEezDvxBRgz6g3ia+Mqxp4F1D/ -XNb0Gqax8F4Gpx9O3pyfzv7y6fSn2aezz6eAINgZGezRlNE81uAwqgiEA7hyqSJtX4NOD3rw5uST -fRDMEjX75mtgN3gyvpYVMHE5hhlPRbiJ7xUwaDilphPEsdMALHg4mYjvxOHz568OCVqxLbYADMyu -0xQfzrRFnyXZKg8n1PgXdumPWUlp/+3y6OsrcXwswl/i2zgMwIdqmjJL/Eji9HlbSOhawZ9xriZB -sJQrEL0biQI6fk5+8YQ7wJJAy1zb6V/yJDPvmSvdIUh/jKkH4DCbLdJYKWw8m4VABOrQ84EOETvX -KHVj6Fhs3a4TjQp+SgkLm2GXKf7Tg2I8p36IBqPodjGNQFw3i1hJbkXTh36zGeqs2WysBwRhJokB -h4vVUChME9RZZQJ+LXEe6rC5ylP8ifBRC5AA4tYKtSQukt46RbdxWks1diYFRByPW2RERZso4kdw -UcZgiZulm0za1DQ8A82AfGkOWrRsUQ4/e+DvgLoymzjc6PHei2mGmP477zQIB3A5Q1T3SrWgsHYU -F6cX4tWLw310Z2DPubTU8ZqjhU6yWtqHK1gtIw+MMPcy8uLSZYV6Fp8e7Ya5iezKdFlhpZe4lJv8 -Vi4BW2RgZ5XFT/QGduYwj0UMqwh6nfwBVqHGb4xxH8qzB2lB3wGotyEoZv3N0u9xMEBmChQRb6yJ -1HrXz6awKPPbBJ2N+Va/BFsJyhItpnFsAmfhPCZDkwgaArzgDCl1J0NQh2XNDivhjSDRXiwbxRoR -uHPU1Ff09SbL77IZ74SPUemOJ5Z1UbA082KDZgn2xHuwQoBkDhu7hmgMBVx+gbK1D8jD9GG6QFna -WwAgMPSKtmsOLLPVoynyrhGHRRiT14KEt5ToL9yaIWirZYjhQKK3kX1gtARCgslZBWdVg2YylDXT -DAZ2SOJz3XnEW1AfQIuKEZjNsYbGjQz9Lo9AOYtzVyk5/dAif/nyhdlGrSm+gojNcdLoQqzIWEbF -FgxrAjrBeGQcrSE2uAPnFsDUSrOm2P8k8oK9MVjPCy3b4AfA7q6qiqODg7u7u0hHF/Ly+kCtDv74 -p2+++dML1onLJfEPTMeRFh1qiw7oHXq00bfGAn1nVq7Fj0nmcyPBGkvyysgVRfy+r5NlLo72J1Z/ -Ihc3Zhr/Na4MKJCZGZSpDLQdNRg9U/vPoldqJJ6RdbZtxxP2S7RJtVbMt7rQo8rBEwC/ZZHXaKob -TlDiK7BusENfynl9HdrBPRtpfsBUUU7Hlgf2X14hBj5nGL4ypniGWoLYAi2+Q/qfmG1i8o60hkDy -oonq7J63/VrMEHf5eHm3vqYjNGaGiULuQInwmzxaAG3jruTgR7u2aPcc19Z8PENgLH1gmFc7lmMU -HMIF12LqSp3D1ejxgjTdsWoGBeOqRlDQ4CTOmdoaHNnIEEGid2M2+7ywugXQqRU5NPEBswrQwh2n -Y+3arOB4QsgDx+IlPZHgIh913r3gpa3TlAI6LR71qMKAvYVGO50DX44NgKkYlX8ZcUuzTfnYWhRe -gx5gOceAkMFWHWbCN64PONob9bBTx+oP9WYa94HARRpzLOpR0AnlYx6hVCBNxdjvOcTilrjdwXZa -HGIqs0wk0mpAuNrKo1eodhqmVZKh7nUWKVqkOXjFVisSIzXvfWeB9kH4uM+YaQnUZGjI4TQ6Jm/P -E8BQt8Pw2XWNgQY3DoMYbRJF1g3JtIZ/wK2g+AYFo4CWBM2CeayU+RP7HWTOzld/GWAPS2hkCLfp -kBvSsRgajnm/J5CMOhoDUpABCbvCSK4jq4MUOMxZIE+44bUclG6CESmQM8eCkJoB3Omlt8HBJxGe -gJCEIuT7SslCfCVGsHxtUX2c7v5dudQEIcZOA3IVdPTi2I1sOFGN41aUw2doP75BZyVFDhw8B5fH -DfS7bG6Y1gZdwFn3FbdFCjQyxWFGExfVK0MYN5j8h2OnRUMsM4hhKG8g70jHjDQJ7HJr0LDgBoy3 -5u2x9GM3YoF9x2GuDuXmHvZ/YZmoRa5Cipm0YxfuR3NFlzYW2/NkPoI/3gKMJlceJJnq+AVGWf6B -QUIPetgH3ZsshkWWcXmXZCEpME2/Y39pOnhYUnpG7uATbacOYKIY8Tx4X4KA0NHnAYgTagLYlctQ -abe/C3bnFEcWLncfeW7z5dGrqy5xp0MRHvvpX6rT+6qMFa5WyovGQoGr1TXgqHRhcnG21YeX+nAb -twllrmAXKT5++iKQEBzXvYu3T5t6w/CIzYNz8j4GddBrD5KrNTtiF0AEtSIyykH4dI58PLJPndyO -iT0ByJMYZseiGEiaT/4ROLsWCsbYX24zjKO1VQZ+4PU3X896IqMukt98PXpglBYx+sR+3PIE7cic -VLBrtqWMU3I1nD4UVMwa1rFtignrc9r+aR676vE5NVo29t3fAj8GCobUJfgIL6YN2bpTxY/vTg3C -03ZqB7DObtV89mgRYG+fz3+BHbLSQbXbOEnpXAEmv7+PytVs7jle0a89PEg7FYxDgr79l7p8AdwQ -cjRh0p2OdsZOTMC5ZxdsPkWsuqjs6RyC5gjMywtwjz+HFU6ve+B7Bge/r7p8IiBvTqMeMmpbbIZ4 -wQclhz1K9gnzfvqMf9dZP27mw4L1/zHLF/+cST5hKgaaNh4+rH5iuXbXAHuEeRpwO3e4hd2h+axy -ZZw7VklKPEfd9VzcUboCxVbxpAigLNnv64GDUqoPvd/WZclH16QCC1nu43HsVGCmlvH8ek3Mnjj4 -ICvExDZbUKzayevJ+4Qv1NFnO5Ow2Tf0c+c6NzErmd0mJfQFhTsOf/j442nYb0IwjgudHm9FHu83 -INwnMG6oiRM+pQ9T6Cld/nH10d66+AQ1GQEmIqzJ1iVsJxBs4gj9a/BARMg7sOVjdtyhL9ZycTOT -lDqAbIpdnaD4W3yNmNiMAj//S8UrSmKDmSzSGmnFjjdmH67qbEHnI5UE/0qnCmPqECUEcPhvlcbX -Ykydlxh60txI0anbuNTeZ1HmmJwq6mR5cJ0shfy1jlPc1svVCnDBwyv9KuLhKQIl3nFOAyctKrmo -y6TaAglileuzP0p/cBrOtzzRsYckH/MwATEh4kh8wmnjeybc0pDLBAf8Ew+cJO67sYOTrBDRc3if -5TMcdUY5vlNGqnsuT4+D9gg5ABgBUJj/aKIjd/4bSa/cA0Zac5eoqCU9UrqRhpycMYQynmCkg3/T -T58RXd4awPJ6GMvr3Vhet7G87sXy2sfyejeWrkjgwtqglZGEvsBV+1ijN9/GjTnxMKfxYs3tMPcT -czwBoijMBtvIFKdAe5EtPt8jIKS2nQNnetjkzyScVFrmHALXIJH78RBLb+ZN8rrTmbJxdGeeinFn -h3KI/L4HUUSpYnPqzvK2jKs48uTiOs3nILYW3WkDYCra6UQcK81uZ3OO7rYs1ejiPz//8PEDNkdQ -I5PeQN1wEdGw4FTGz+PyWnWlqdn8FcCO1NJPxKFuGuDeIyNrPMoe//OOMjyQccQdZSjkogAPgLK6 -bDM39ykMW891kpR+zkzOh03HYpRVo2ZSA0Q6ubh4d/L5ZEQhv9H/jlyBMbT1pcPFx7SwDbr+m9vc -Uhz7gFDr2FZj/Nw5ebRuOOJhG2vAdjzf1oPDxxjs3jCBP8t/KqVgSYBQkQ7+PoVQj945/Kb9UIc+ -hhE7yX/uyRo7K/adI3uOi+KIft+xQ3sA/7AT9xgzIIB2ocZmZ9DslVtK35rXHRR1gD7S1/vNe832 -1qu9k/EpaifR4wA6lLXNht0/75yGjZ6S1ZvT788+nJ+9uTj5/IPjAqIr9/HTwaE4/fGLoPwQNGDs -E8WYGlFhJhIYFrfQSSxz+K/GyM+yrjhIDL3enZ/rk5oNlrpg7jPanAiecxqThcZBM45C24c6/wgx -SvUGyakponQdqjnC/dKG61lUrvOjqVRpjs5qrbdeulbM1JTRuXYE0geNXVIwCE4xg1eUxV6ZXWHJ -J4C6zqoHKW2jbWJISkHBTrqAc/5lTle8QCl1hidNZ63oL0MX1/AqUkWawE7udWhlSXfD9JiGcfRD -e8DNePVpQKc7jKwb8qwHsUCr9Trkuen+k4bRfq0Bw4bB3sG8M0npIZSBjcltIsRGfJITynv4apde -r4GCBcODvgoX0TBdArOPYXMt1glsIIAn12B9cZ8AEFor4R8IHDnRAZljdkb4drPc/3OoCeK3/vnn -nuZVme7/TRSwCxKcShT2ENNt/A42PpGMxOnH95OQkaPUXPHnGssDwCGhAKgj7ZS/xCfos7GS6Urn -l/j6AF9oP4Fet7qXsih1937XOEQJeKbG5DU8U4Z+IaZ7WdhTnMqkBRorHyxmWEHopiGYz574tJZp -qvPdz96dn4LviMUYKEF87nYKw3G8BI/QdfIdVzi2QOEBO7wukY1LdGEpyWIZec16g9YoctTby8uw -60SB4W6vThS4jBPloj3GaTMsU04QISvDWphlZdZutUEKu22I4igzzBKzi5ISWH2eAF6mpzFviWCv -hKUeJgLPp8hJVpmMxTRZgB4FlQsKdQpCgsTFekbivDzjGHheKlMGBQ+LbZlcrys83YDOEZVgYPMf -T76cn32gsoTDV43X3cOcU9oJTDmJ5BhTBDHaAV/ctD/kqtmsj2f1K4SB2gf+tF9xdsoxD9Dpx4FF -/NN+xXVox85OkGcACqou2uKBGwCnW5/cNLLAuNp9MH7cFMAGMx8MxSKx7EUnerjz63KibdkyJRT3 -MS+fcICzKmxKmu7spqS1P3qOqwLPuZbj/kbwtk+2zGcOXW86b4aS39xPRwqxJBYw6rb2xzDZYZ2m -ejoOsw1xC21rtY39OXNipU67RYaiDEQcu50nLpP1K2HdnDnQS6PuABPfanSNJPaq8tHP2Uh7GB4m -ltidfYrpSGUsZAQwkiF17U8NPhRaBFAglP07diR3Onl+6M3RsQYPz1HrLrCNP4Ai1Lm4VOORl8CJ -8OVXdhz5FaGFevRIhI6nkskst3li+Llbo1f50p9jrwxQEBPFroyzazlmWFMD8yuf2AMhWNK2Hqkv -k6s+wyLOwDm9H+Dwrlz0H5wY1FqM0Gl3I7dtdeSTBxv0loLsJJgPvozvQPcXdTXmlRw4h+6tpRuG -+jBEzD6Epvr0fRxiOObXcGB9GsC91NCw0MP7deDsktfGOLLWPraqmkL7QnuwixK2ZpWiYxmnONH4 -otYLaAzucWPyR/apThSyv3vqxJyYkAXKg7sgvbmNdINWOGHE5UpcOZpQOnxTTaPfLeWtTMFogJEd -Y7XDL7baYRLZcEpvHthvxu5ie7Htx43eNJgdmXIMRIAKMXoDPbsQanDAFf5Z70Ti7Iac47d/PZuK -tx9+gn/fyI9gQbHmcSr+BqOLt3kJ20ou2qXbFLCAo+L9Yl4rLIwkaHRCwRdPoLd24ZEXT0N0ZYlf -UmIVpMBk2nLDt50AijxBKmRv3ANTLwG/TUFXywk1DmLfWoz0S6TBcI0L1oUc6JbRutqkaCac4Eiz -iJej87O3px8+nUbVPTK2+Tlygid+HhZORx8Nl3gMNhX2yaLGJ1eOv/yDTIsed1nvNU29DO41RQjb -kcLuL/kmjdjuKeISAwai2C7zRYQtgdO5RK+6A/954mwrH7TvnnFFWOOJPjxrnHh8DNQQP7f1zwga -Uh89J+pJCMVzrBXjx9Go3wJPBUW04c/zm7ulGxDXRT80wTamzazHfnerAtdMZw3PchLhdWyXwdSB -pkmsNvOFWx/4MRP6IhRQbnS8IVdxnVZCZrCVor093UgBCt4t6WMJYVZhK0Z1bhSdSe/irXJyj2Il -RjjqiIrq8RyGAoWw9f4xvmEzgLWGouYSaIBOiNK2KXe6qnqxZgnmnRBRryff4C7JXrnJL5rCPChv -jBeN/wrzRG+RMbqWlZ4/PxhPLl82CQ4UjF54Bb2LAoydyyZ7oDGL58+fj8S/Pez0MCpRmuc34I0B -7F5n5ZxeDxhsPTm7Wl2H3ryJgB8Xa3kJD64oaG6f1xlFJHd0pQWR9q+BEeLahJYZTfuWOeZYXcnn -y9yCz6m0wfhLltB1RxhRkqhs9a1RGG0y0kQsCYohjNUiSUKOTsB6bPMaa/Ewuqj5Rd4DxycIZopv -8WCMd9hrdCwpb9Zyj0XnWIwI8IhSyng0KmamajTAc3ax1WjOzrKkaspIXrhnpvoKgMreYqT5SsR3 -KBlmHi1iOGWdHqs2jnW+k0W9jUq+uHTjjK1Z8uuHcAfWBknLVyuDKTw0i7TIZbkw5hRXLFkklQPG -tEM43JkubyLrEwU9KI1AvZNVWFqJtm//YNfFxfQjHR/vm5F01lBlL8TimFCctfIKo6gZn6JPlpCW -b82XCYzygaLZ2hPwxhJ/0LFUrCHw7u1wyxnrTN/HwWkbzSUdAIfugLIK0rKjpyOci8csfGbagVs0 -8EM7c8LtNimrOk5n+tqHGfppM3uervG0ZXA7CzyttwK+fQ6O777O2AfHwSTXID0x49ZUZByLlY5M -RG5lmV+EVeTo5R2yrwQ+BVJmOTP10CZ2dGnZ1Raa6gRHR8UjqK9M8dKAQ26qZjoFJy7mU0pvMuUO -A86zn29JV1eI78T41VQctnY+i2KLNzkBss+Woe+KUTeYihMMMHNs34shvjsW45dT8ccd0KOBAY4O -3RHa+9gWhEEgr66eTMY0mRPZwr4U9of76hxG0PSM4+SqTf4umb4lKv1ri0pcIagTlV+2E5VbYw/u -WzsfH8lwA4pjlcjl/jOFJNRIN7p5mMEJPyyg37M5Wrp2vKmoocK5OWxG7ho96GhE4zbbQUxRulZf -XL+LuoYNp71zwKTJtFIV7S1zmMao0WsRFQDM+o7S8Bve7QLvNSlc/2zwiFUXAViwPREEXenJB2ZN -w0ZQH3QEn6QBHmAUEeJhaqMoXMl6goiEdA8OMdFXrUNsh+N/d+bhEoOho9AOlt98vQtPVzB7izp6 -FnR3pYUnsra8ollu8+kPzHmM0tf1NwmMA6URHXBWzVWV5GYeYfYy30GT2yzmDV4GSSfTaBJT6bpN -vJXmW7/Qj6HYASWTwVqAJ1Wv8CD5lu62PFGU9IZX1Hx9+HJqKoMZkJ7Aq+jVV/oKSOpmLj/wfeyp -3rvBS93vMPoXB1hS+b3tq85uhqZ13LoLyh8spOjZJJpZOjSG6eE6kGbNYoF3JjbEZN/aXgDyHryd -Ofg55vLTHBw22JBGfei6GqOR3iHVNiDAD5uMIcl5VNdGkSLSu4RtSHnuUpxPFgXdq9+CYAgBOX8d -8xt0BeviyIbYjE3Bk8+xm82Jn+qmt+6M7Qka2+om3DV97r9r7rpFYGdukhk6c/frS10a6L7DVrSP -Bhze0IR4VIlEo/H7jYlrB6Y6h6Y/Qq8/SH63E850wKw8BMZk7GC8n9hTY2/M/iZeuN8xIWyfL2R2 -y4l7nY3WtDs2o83xj/EUOPkFn9sbBiijaak5kPdLdMPejHNkZ/L6Ws1ivN1xRptsyufq7J7Mtu09 -Xc4nY7U1uy28tAhAGG7Smbducj0wBuhKvmWa06Gc22kEDU1Jw04WskqWbBL01g7ARRwxpf4mEM9p -xKNUYqBb1WVRwm54pO8i5jydvtTmBqgJ4G1idWNQNz2m+mpaUqyUHGZKkDlO20ryASKwEe+YhtnM -vgNeedFcs5BMLTPIrN7IMq6aK4b8jIAENl3NCFR0jovrhOcaqWxxiYtYYnnDQQoDZPb7V7Cx9DbV -O+5VmFht93h2oh465PuUKxscY2S4OLm31wu611ot6Wpr1zu0zRqus1cqwTKYu/JIR+pYGb/V93fx -HbMcyUf/0uEfkHe38tLPQrfqjL1bi4bzzFUI3Qub8MYAMs599zB2OKB742JrA2zH9/WFZZSOhznQ -2FJR++S9CqcZbdJEkDBh9IEIkl8U8MQIkgf/kREkfWsmGBqNj9YDvWUCD4SaWD24V1A2jAB9ZkAk -PMBuXWBoTOXYTbovcpXcj+yF0qwrnUo+Yx6QI7t3kxEIvmpSuRnK3lVwuyJIvnTR4+/PP745OSda -zC5O3v7HyfeUlIXHJS1b9egQW5bvM7X3vfRvN9ymE2n6Bm+w7bkhlmuYNITO+04OQg+E/nq1vgVt -KzL39VCHTt1PtxMgvnvaLahDKrsXcscv0zUmbvpMK0870E85qdb8cjITzCNzUsfi0JzEmffN4YmW -0U5seWjhnPTWrjrR/qq+BXQg7j2xSda0Anhmgvxlj0xMxYwNzLOD0v7ffFBmOFYbmht0QAoX0rnJ -kS5xZFCV//8TKUHZxbi3Y0dxau/mpnZ8PKTspfN49ruQkSGIV+436s7PFfalTAeoEASs8PQ9hYyI -0X/6QNWmHzxT4nKfCov3Udlc2V+4Ztq5/WuCSQaVve9LcYISH7NC41WduokDtk+nAzl9dBqVr5xK -FtB8B0DnRjwVsDf6S6wQ51sRwsZRu2SYHEt01Jf1Ocij3XSwN7R6IfaHyk7dskshXg43XLYqO3WP -Q+6hHuihalPc51hgzNIcqicV3xFkPs4UdMGX53zgGbre9sPX28uXR/ZwAfkdXzuKhLLJRo5hv3Sy -MXdeKul0J2Ypp5Suh3s1JySsW1w5UNknGNrbdEpSBvY/Js+BIY289/0hM9PDu3p/1MbUst4RTEmM -n6kJTcsp4tG42yeT7nQbtdUFwgVJjwDSUYEAC8F0dKOTILrlLO/xC70bnNd0Ha97whQ6UkHJYj5H -cA/j+zX4tbtTIfGjujOKpj83aHOgXnIQbvYduNXEC4UMm4T21Bs+GHABuCa7v//LR/TvpjHa7oe7 -/Grb6lVvHSD7spj5iplBLRKZxxEYGdCbY9LWWC5hBB2voWno6DJUMzfkC3T8KJsWL9umDQY5szPt -AVijEPwfucjncQ== -""") - -##file activate.sh -ACTIVATE_SH = convert(""" + b = base64.b64decode(s.encode("ascii")) + return zlib.decompress(b).decode("utf-8") + + +# file site.py +SITE_PY = convert( + """ +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 +3WFNNa14+S9FG+TYTrVfYA1F8L80iX54 +""" +) + +# file activate.sh +ACTIVATE_SH = convert( + """ eJytVd9v2kAMfs9fYQLq2m4MscdNVKMqEkgtVIQxbeuUHolpTgsXdHehpT/+9/mSEBJS2MOaB0ji z77P9menDpOAK5jzEGERKw0zhFihD/dcB2CrKJYewoyLFvM0XzGNNpzOZbSAGVPBqVWHdRSDx4SI NMhYANfgc4meDteW5ePGC45P4MkCumKhUENzDsu1H3lw1vJx1RJxGMKns6O2lWDqINGgotAHFCsu @@ -2007,10 +2062,12 @@ YOgOu1c91/2cwYpznPPeDoQpGL2xSm09NKp7BsvQ2hnT3aMs07lUnskpxewvBk73/LLnXo9HV9eT ijB3hWBO2ygoiWg/bKuZxqCCQq0DD3vkWIVvI2KosIw+vqW1gIItEG5KJb+xb09g65ktwYKgTc51 uGJ/EFQs0ayEWLCQM5V9N4g+1+8UbXOJzF8bqhKtIqIwicWvzNFROZJlpfD8A7Vc044R0FxkcezG VzsV75usvTdYef+57v5n1b225qhXfwEmxHEs -""") +""" +) -##file activate.fish -ACTIVATE_FISH = convert(""" +# file activate.fish +ACTIVATE_FISH = convert( + """ eJyFVVFv2zYQftevuMoOnBS1gr0WGIZ08RADSRw4boBhGGhGOsUcKFIjKbUu9uN7lC2JsrXWDzZM fnf38e6+uwlsdsJCLiRCUVkHrwiVxYy+hHqDbQKvQl3z1ImaO0xyYXdbeP9FuJ1QwMFUSnmcP4dL 2DlXfry+9v/sDqVMUl3AFVi0Vmj1PokmcKtBaecNQTjIhMHUyX0SRXmlKIpWkGEbDuYZzBZfCVcL @@ -2026,10 +2083,12 @@ Bmo5XuOA0NQ67ir7AXJtQhtLKO7XhC0l39PGOBsHPvzBuHUSjoOnA0ldozGC9gZ5rek3+y3ALHO/ kT7AP379lQZLSnFDLtwWihfYxw4nZd+ZR7myfkI2ZTRCuRxmF/bCzkbhcElvYamW9PbDGrvqPKC0 +D/uLi/sFcxGjOHylYagZzzsjjhw206RQwrWIwOxS2dnk+40xOjX8bTPegz/gdWVSXuaowNuOLda wYyNuRPSTcd/B48Ppeg= -""") +""" +) -##file activate.csh -ACTIVATE_CSH = convert(""" +# file activate.csh +ACTIVATE_CSH = convert( + """ eJx1U2FP2zAQ/e5f8TAV3Soo+0zXbYUiDQkKQgVp2ibjJNfFUuIg22nVf885SVFLO3+I7Lt3fr6X d8eY58ZjYQpCWfuAhFB7yrAyIYf0Ve1SQmLsuU6DWepAw9TnEoOFq0rwdjAUx/hV1Ui1tVWAqy1M QGYcpaFYx+yVI67LkKwx1UuTEaYGl4X2Bl+zJpAlP/6V2hTDtCq/DYXQhdEeGW040Q/Eb+t9V/e3 @@ -2038,29 +2097,36 @@ kaYB/peoyY7aVHzpJnE9e+6I5Z+ji4GMTNJWNuOQq6MA1N25p8pW9HWdVWlfsNpPDbdxjgpaahuw 1M7opCA/FFu1uwxC7L8KUqmto1KyQe3rx0I0Eovdf7BVe67U5c1MzSZ310pddGheZoFPWyytRkzU aCA/I+RkBXhFXr5aWV0SxjhUI6jwdAj8kmhPzX7nTfJFkM3MImp2VdVFFq1vLHSU5szYQK4Ri+Jd xlW2JBtOGcyYVW7SnB3v6RS91g3gKapZ0oWxbHVteYIIq3iv7QeuSrUj6KSqQ+yqsxDj1ivNQxKF -YON10Q+NH/ARS95i5Tuqq2Vxfvc23f/FO6zrtXXmJr+ZtMY9/A15ZXFWtmch2rEQ4g1ryVHH -""") +YON10Q+NH/ARS95i5Tuqq2Vxfvc23f/FO6zrtXXmJr+ZtMY9/A15ZXFWtmch2rEQbxoCUb0= +""" +) -##file activate.bat -ACTIVATE_BAT = convert(""" + +# file activate.bat +ACTIVATE_BAT = convert( + """ eJx9Ul9LhEAQfxf8DoOclI/dYyFkaCmcq4gZQTBUrincuZFbff12T133TM+nnd35/Zvxlr7XDFhV mUZHOVhFlOWP3g4DUriIWoVomYZpNBWUtGpaWgImO191pFkSpzlcmgaI70jVX7n2Qp8tuByg+46O CMHbMq64T+nmlJt082D1T44muCDk2prgEHF4mdI9RaS/QwSt3zSyIAaftRccvqVTBziD1x/WlPD5 xd729NDBb8Nr4DU9QNMKsJeH9pkhPedhQsIkDuCDCa6A+NF9IevVFAohkqizdHetg/tkWvPoftWJ MCqnOxv7/x7Np6yv9P2Ker5dmX8yNyCkkWnbZy3N5LarczlqL8htx2EM9rQ/2H5BvIsIEi8OEG8U +g8CsNTr -""") - -##file deactivate.bat -DEACTIVATE_BAT = convert(""" -eJyFkN0KgkAUhO8F32EQpHqFQEjQUPAPMaErqVxzId3IrV6/XST/UDx3c86c4WMO5FYysKJQFVVp -CEfqxsnJ9DI7SA25i20fFqs3HO+GYLsDZ7h8GM3xfLHrg1QNvpSX4CWpQGvokZk4uqrQAjXjyElB -a5IjCz0r+2dHcehHCe5MZNmB5R7TdqMqECMptHZh6DN/utb7Zs6Cej8OXYE5J04YOKFvD4GkHuJ0 -pilSd1jG6n87tDZ+BUwUOepI6CGSkFMYWf0ihvT33Qj1A+tCkSI= -""") - -##file activate.ps1 -ACTIVATE_PS = convert(""" +""" +) + +# file deactivate.bat +DEACTIVATE_BAT = convert( + """ +eJyFkN0KgkAUhO8X9h0GQapXCIQEDQX/EBO6kso1F9KN3Or1201Si6JzN+fMGT5mxQ61gKgqSijp +mETup9nGDgo3yi29S90QjmhnEteOYb6AFNjdBC9xvoj9iTUd7lzWkDVrwFuYiZ15JiW8QiskSlbx +lpUo4sApXtlJGodJhqNQWW7k+Ou831ACNZrC6BeW+eXPNEbfl7OiXr6H/oHZZl4ceXHoToG0nuIM +pk+k4fAba/wd0Pr4P2CqyLeOlJ4iKfkJo6v/iaH9YzfPMEoeMG2RUA== +""" +) + +# file activate.ps1 +ACTIVATE_PS = convert( + """ eJylWdmO41hyfW+g/0FTU7C7IXeJIqmtB/3AnZRIStxF2kaBm7gv4ipyMF/mB3+Sf8GXVGVl1tLT 43ECSqR4b5wbETeWE8z/+a///vNCDaN6cYtSf5G1dbNw/IVXNIu6aCvX9xa3qsgWl0IJ/7IYinbh 2nkOVqs2X0TNjz/8eeFFle826fBhQRaLBkD9uviw+LCy3Sbq7Mb/UNbrH3+YNtLcVaB+Xbipb+eL @@ -2148,58 +2214,65 @@ tsd7dVEfJFmc15IYqwHverrpWyS1rFZibDPW1hUUb+85CGUzSBSTK8hpvee/ZxonW51TUXekMy3L uy25tMTg4mqbSLQQJ+skiQu2toIfBFYrOWql+EQipgfT15P1aq6FDK3xgSjIGWde0BPftYchDTdM i4QdudHFkN0u6fSKiT09QLv2mtSblt5nNzBR6UReePNs+khE4rHcXuoK21igUKHl1c3MXMgPu7y8 rKQDxR6N/rffXv+lROXet/9Q+l9I4D1U -""") - -##file distutils-init.py -DISTUTILS_INIT = convert(""" -eJytV1uL4zYUfvevOE0ottuMW9q3gVDa3aUMXXbLMlDKMBiNrSTqOJKRlMxkf33PkXyRbGe7Dw2E -UXTu37lpxLFV2oIyifAncxmOL0xLIfcG+gv80x9VW6maw7o/CANSWWBwFtqeWMPlGY6qPjV8A0bB -C4eKSTgZ5LRgFeyErMEeOBhbN+Ipgeizhjtnhkn7DdyjuNLPoCS0l/ayQTG0djwZC08cLXozeMss -aG5EzQ0IScpnWtHSTXuxByV/QCmxE7y+eS0uxWeoheaVVfqSJHiU7Mhhi6gULbOHorshkrEnKxpT -0n3A8Y8SMpuwZx6aoix3ouFlmW8gHRSkeSJ2g7hU+kiHLDaQw3bmRDaTGfTnty7gPm0FHbIBg9U9 -oh1kZzAFLaue2R6htPCtAda2nGlDSUJ4PZBgCJBGVcwKTAMz/vJiLD+Oin5Z5QlvDPdulC6EsiyE -NFzb7McNTKJzbJqzphx92VKRFY1idenzmq3K0emRcbWBD0ryqc4NZGmKOOOX9Pz5x+/l27tP797c -f/z0d+4NruGNai8uAM0bfsYaw8itFk8ny41jsfpyO+BWlpqfhcG4yxLdi/0tQqoT4a8Vby382mt8 -p7XSo7aWGdPBc+b6utaBmCQ7rQKQoWtAuthQCiold2KfJIPTT8xwg9blPumc+YDZC/wYGdAyHpJk -vUbHbHWAp5No6pK/WhhLEWrFjUwtPEv1Agf8YmnsuXUQYkeZoHm8ogP16gt2uHoxcEMdf2C6pmbw -hUMsWGhanboh4IzzmsIpWs134jVPqD/c74bZHdY69UKKSn/+KfVhxLgUlToemayLMYQOqfEC61bh -cbhwaqoGUzIyZRFHPmau5juaWqwRn3mpWmoEA5nhzS5gog/5jbcFQqOZvmBasZtwYlG93k5GEiyw -buHhMWLjDarEGpMGB2LFs5nIJkhp/nUmZneFaRth++lieJtHepIvKgx6PJqIlD9X2j6pG1i9x3pZ -5bHuCPFiirGHeO7McvoXkz786GaKVzC9DSpnOxJdc4xm6NSVq7lNEnKdVlnpu9BNYoKX2Iq3wvgh -gGEUM66kK6j4NiyoneuPLSwaCWDxczgaolEWpiMyDVDb7dNuLAbriL8ig8mmeju31oNvQdpnvEPC -1vAXbWacGRVrGt/uXN/gU0CDDwgooKRrHfTBb1/s9lYZ8ZqOBU0yLvpuP6+K9hLFsvIjeNhBi0KL -MlOuWRn3FRwx5oHXjl0YImUx0+gLzjGchrgzca026ETmYJzPD+IpuKzNi8AFn048Thd63OdD86M6 -84zE8yQm0VqXdbbgvub2pKVnS76icBGdeTHHXTKspUmr4NYo/furFLKiMdQzFjHJNcdAnMhltBJK -0/IKX3DVFqvPJ2dLE7bDBkH0l/PJ29074+F0CsGYOxsb7U3myTUncYfXqnLLfa6sJybX4g+hmcjO -kMRBfA1JellfRRKJcyRpxdS4rIl6FdmQCWjo/o9Qz7yKffoP4JHjOvABcRn4CZIT2RH4jnxmfpVG -qgLaAvQBNfuO6X0/Ux02nb4FKx3vgP+XnkX0QW9pLy/NsXgdN24dD3LxO2Nwil7Zlc1dqtP3d7/h -kzp1/+7hGBuY4pk0XD/0Ao/oTe/XGrfyM773aB7iUhgkpy+dwAMalxMP0DrBcsVw/6p25+/hobP9 -GBknrWExDhLJ1bwt1NcCNblaFbMKCyvmX0PeRaQ= -""") - -##file distutils.cfg -DISTUTILS_CFG = convert(""" +""" +) + +# file distutils-init.py +DISTUTILS_INIT = convert( + """ +eJytV21v5DQQ/u5fMaRCJLANcHxBlVYI7g504nSgU7+gqorcxNk1zdrB9m679+uZsfPivGyPD0Sq +5PWMZ8bPPDPjykOrjQN5aJkMS237lT0PyydulFQ7y9gV6LbUlQBpQWkHHE7SuCNvhDrBQVfHRmzA +angSUHIFR4uaDpyGWqoK3F6AdVUjH9DQO2+bK/cF3OIBbR5BK2jP7XmDimj/cLQOHgT6CIZxlzsw +wspKWJCKzKEdtHbdnt1eq29RT9ZSVNfP+Tn/BJU0onTanIfL+dgZQ4HiBwFbvG7ecrfPux0SWXd0 +srEF7Ucaf2up0pl6GgzmRVHLRhRFtoFkMJBkTNbDcaXNgRbp1EEG20UQ6eLMYD+7YYBfn4+cFmly +i7BGaRg8QMvLR75DBB18aYG3reDGUjYQ1YAfWMKh0SV3EtHnNmyerROH0dBPeBfRWBG8Fz7yosil +ssK49LsNzC8FV8iOf/gN/Prjq+/9ISN4U4yRbYlzeaN5VYTkpkkxXmFUTDbwQSsx97CBNEER/ZGd +P3//rXjz7uPb17d/fPwry7zDK3it27O/jhGNOCHREAdn5MPRCetVnDmHG4VbGXGSFlEoCgxvGm8e +S/0R8VyK1sHPvcW3xmgzWmu5tR1YJ2EuWx2EjNVGR5BDR1na2FBCSq1quaN7SYuCG/soW8aGKzxw +KyzGonasC+0DZjaKalTAOHBBtYxQlnt4OMqmKsSzg5GcUGlh1VcOHpV+gj3+IWt2wnk8seJsVFze +zp6K9wmLXD9ZuKai33NTUXUESpEKUtDoY9cHvG9R0dXy1ohaPmeMCsb/brirkfxUHAka/eFVEi4x +xSgv9eHAVZWPN+hQGzeQ0RqXwwbzdsoG8zNqpROVbExjJWrqXLyRn0ShW6oRm1rR1JEOfRQ37uaI +jOHmjCnGOsMWRtydatK3VN3C3f1ETTRoEvmmLHbIUqSLI5soodl/c7HYy23bSNe3GyvajLEXjUQV +P2mLlDNP7ZBILMz3SJGkq8T+m4Ccr8PKXkjzanKHH10fCQbmuxFDthBx4SryQquOlfaGMYqWhlYR +Cs93YEKR1PI30oa6x8jzhRbDMRKIM92PmVP7QtjCqpsOi45ZCHWYVlgMrbbyORnzjQPW+DPdPEvy +9hwBV++S0K2G5r16aPXMXGuR8T7ZE8U4aq8uLYnSqdIYC5Y5NgscNjiPGgwi9cAsy4t0cqEq+yRx +IC4iXikBbwhpedAnkdLxjE1FNA9Vla6Eb4Q7GhXUWHgTfCbliM8KDWJ6jS18yjFsqkV4vhRSlVSm +vWI+FXWsGsSzkyk1zcK2osQnULnFEg352VIP6uBBHMPmsjd1+959XMsxHstwp057l1jF7FKYOPMq +XfphuDTXC9klDGJ4ijk8M3vYuC6hSQ/QF9BE8RJNasQVjjSSXkQ3VgJqWf8j3IuopjF9FnzUuQx+ +JFwHf4ZmMUezt9eJTzyMnImpSLYKfyRPv+ZmZztgPT6dxRU/ne6Qg5ceEPRhvDTN1lradIg1fogN +56YTeQiK3qaly3y6k/fvfsGHaOL/N8KONihN29OwfdcfuMdo+rjwicftIz6NqDfyphmOzh8FUQjU +OmchoHvC5YLn/jHq19/AXef8fuqdzMaUHI4sSBblY4VlK1J2kRsLnsW8+Rc/zwIT +""" +) + +# file distutils.cfg +DISTUTILS_CFG = convert( + """ eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg 9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q= -""") - -##file activate_this.py -ACTIVATE_THIS = convert(""" -eJyNU01v2zAMvetXEB4K21jnDOstQA4dMGCHbeihlyEIDMWmE62yJEiKE//7kXKdpEWLzYBt8evx -kRSzLPs6wiEoswM8YdMpjUXcq1Dz6RZa1cSiTkJdr86GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe -5a3p0cRKiEe2NtLAFikftnDco0ko/SFEVgEZ8aRCZDIPY9xbA8pE9M4jfW/B2CjiHq9zbJVZuOQq -siwTIvpxKYCembPAU4Muwi/Z4zfvrZ/MXipKeB8C+qisSZYiWfjJfs+0/MFMdWn1hJcO5U7G/SLa -xVx8zU6VG/PXLXvfsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCJN9dzKaoexyB/uH79TnjwvxcW0ntSb -yZ8jq1Z5Q1UXsyy3gf9nbjTEj7NzQMfCJa/YSmrQ+2D/BqfiOi6sclrGzvoeVivIj8rcfcmnIQRF -7XCyeZI7DFe5/lhlCs5PRf5QW66VXT/NrlQ46oD/D6InkOmi3IQcbhKxAX2g4a+Xd5s3UtCtG2py -m8eg6WYWqR6SL5OjKMGfSrYt/6kxxQtOpeAgj1LXBNmpE2ElmCSIy5H0zFd8gJ924HWijWhb2hRC -6wNEm1QdDZtuSZcEprIUBo/XRNcbQe1OUbQ/r3hPTaPJJDNtFLu8KHV5XoNr3Eo6h6YtOKw8e8yw -VF5PnJ+ts3a9/Mz38RpG/AUSzYUW -""") - -##file python-config -PYTHON_CONFIG = convert(""" +""" +) + +# file activate_this.py +ACTIVATE_THIS = convert( + """ +eJyNU8Fu2zAMvesrCA1FbSxzhvUWIIcOGLDDNvTQyxAEhmLTiVZZMiTFif9+pFwnbtFiM2BbFJ8e ++ShSSvl1gGPQdg94xqrRBrN40KHk1QJqXcWsTEZZri+OPIfBHeGkjRGqirpXEYG90Gsfj8qg7YFe +7Z1t0cZCiEf2VsrCDike1nA6oE0s7TFE3gJy4lmHyMk8DPHgLGgb0Xce6bsA66KIB5zH2Gm77BJU +SCmFiH5YCaBnylngucIuwi/V4jfvnR/dXmkKeB8C+qidTZ4sefiRv6e0/NGOuox+wmuFbjsVD8vo +lpP4kkFFN9y+Ltn7yDyXKWAudNs5H8GFaRV0xMt6CEI4U5culMwFawIWz7Ut9hgz+XD/+F0uQMpc +XF2bcXs74vlkUWtvqQzZZKtd4P8lWbrVjxM4YMfGNa7YKarY+2T/JiehDcspOqNi43wL6zXIk7Z3 +X+R4K6ybglVPao9hFuuP0zbj+CTyh96xVoZ+mqAkHE3A/ycxI8nYOTdBwk1KrEcfqBs2q7vtGyGo +DfuSYNM1GGrVLOkhOxeC8YWqa/5TNbIXieSCkR6VKYmn0WciSGeTIa5L2uckxQf46XoeKpqLuqZ5 +IbY2QHRpq6Ebpo5pksHxV8LiaZ7dZiuoxukUTdGrZMdK0XUkN80VQ17oW12GYc5bqK5DW2d8LL8g +JlqS11LOz95pd7P6zE04pxF/AX70hVA= +""" +) + +# file python-config +PYTHON_CONFIG = convert( + """ eJyNVV1P2zAUfc+v8ODBiSABxlulTipbO6p1LWqBgVhlhcZpPYUkctzSivHfd6+dpGloGH2Ja/ue e+65Hz78xNhtf3x90xmw7vCWsRPGLvpDNuz87MKfdKMWSWxZ4ilNpCLZJiuWc66SVFUOZkkcirll rfxIBAzOMtImDzSVPBRrekwoX/OZu/0r4lm0DHiG60g86u8sjPw5rCyy86NRkB8QuuBRSqfAKESn @@ -2215,17 +2288,18 @@ LTgxRXACpvnQv/PuT0xCCAywY/K4hE6Now2qDwaSE5FB+1agsoUveYDepS83qFcF1NufvULD3fTl g6Hgf7WBt6lzMeiyyWVn3P1WVbwaczHmTzE9A5SyItTVgFYyvs/L/fXlaNgbw8v3azT+0eikVlWD /vBHbzQumP23uBCjsYdrL9OWARwxs/nuLOzeXbPJTa/Xv6sUmQir5pC1YRLz3eA+CD8Z0XpcW8v9 MZWF36ryyXXf3yBIz6nzqz8Muyz0m5Qj7OexfYo/Ph3LqvkHUg7AuA== -""") +""" +) -MH_MAGIC = 0xfeedface -MH_CIGAM = 0xcefaedfe -MH_MAGIC_64 = 0xfeedfacf -MH_CIGAM_64 = 0xcffaedfe -FAT_MAGIC = 0xcafebabe -BIG_ENDIAN = '>' -LITTLE_ENDIAN = '<' -LC_LOAD_DYLIB = 0xc -maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint') +MH_MAGIC = 0xFEEDFACE +MH_CIGAM = 0xCEFAEDFE +MH_MAGIC_64 = 0xFEEDFACF +MH_CIGAM_64 = 0xCFFAEDFE +FAT_MAGIC = 0xCAFEBABE +BIG_ENDIAN = ">" +LITTLE_ENDIAN = "<" +LC_LOAD_DYLIB = 0xC +maxint = majver == 3 and getattr(sys, "maxsize") or getattr(sys, "maxint") class fileview(object): @@ -2244,16 +2318,14 @@ class fileview(object): self._pos = 0 def __repr__(self): - return '<fileview [%d, %d] %r>' % ( - self._start, self._end, self._fileobj) + return "<fileview [%d, %d] %r>" % (self._start, self._end, self._fileobj) def tell(self): return self._pos def _checkwindow(self, seekto, op): if not (self._start <= seekto <= self._end): - raise IOError("%s to offset %d is outside window [%d, %d]" % ( - op, seekto, self._start, self._end)) + raise IOError("%s to offset %d is outside window [%d, %d]" % (op, seekto, self._start, self._end)) def seek(self, offset, whence=0): seekto = offset @@ -2264,15 +2336,15 @@ class fileview(object): elif whence == os.SEEK_END: seekto += self._end else: - raise IOError("Invalid whence argument to seek: %r" % (whence,)) - self._checkwindow(seekto, 'seek') + raise IOError("Invalid whence argument to seek: {!r}".format(whence)) + self._checkwindow(seekto, "seek") self._fileobj.seek(seekto) self._pos = seekto - self._start def write(self, bytes): here = self._start + self._pos - self._checkwindow(here, 'write') - self._checkwindow(here + len(bytes), 'write') + self._checkwindow(here, "write") + self._checkwindow(here + len(bytes), "write") self._fileobj.seek(here, os.SEEK_SET) self._fileobj.write(bytes) self._pos += len(bytes) @@ -2280,7 +2352,7 @@ class fileview(object): def read(self, size=maxint): assert size >= 0 here = self._start + self._pos - self._checkwindow(here, 'read') + self._checkwindow(here, "read") size = min(size, self._end - here) self._fileobj.seek(here, os.SEEK_SET) bytes = self._fileobj.read(size) @@ -2293,7 +2365,7 @@ def read_data(file, endian, num=1): Read a given number of 32-bits unsigned integers from the given file with the given endianness. """ - res = struct.unpack(endian + 'L' * num, file.read(num * 4)) + res = struct.unpack(endian + "L" * num, file.read(num * 4)) if len(res) == 1: return res[0] return res @@ -2312,7 +2384,7 @@ def mach_o_change(path, what, value): if bits == 64: read_data(file, endian) # The header is followed by ncmds commands - for n in range(ncmds): + for _ in range(ncmds): where = file.tell() # Read command header cmd, cmdsize = read_data(file, endian, 2) @@ -2324,11 +2396,11 @@ def mach_o_change(path, what, value): file.seek(where + name_offset, os.SEEK_SET) # Read the NUL terminated string load = file.read(cmdsize - name_offset).decode() - load = load[:load.index('\0')] + load = load[: load.index("\0")] # If the string is what is being replaced, overwrite it. if load == what: file.seek(where + name_offset, os.SEEK_SET) - file.write(value.encode() + '\0'.encode()) + file.write(value.encode() + "\0".encode()) # Seek to the next command file.seek(where + cmdsize, os.SEEK_SET) @@ -2339,7 +2411,7 @@ def mach_o_change(path, what, value): if magic == FAT_MAGIC: # Fat binaries contain nfat_arch Mach-O binaries nfat_arch = read_data(file, BIG_ENDIAN) - for n in range(nfat_arch): + for _ in range(nfat_arch): # Read arch header cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5) do_file(file, offset, size) @@ -2352,13 +2424,13 @@ def mach_o_change(path, what, value): elif magic == MH_CIGAM_64: do_macho(file, 64, LITTLE_ENDIAN) - assert(len(what) >= len(value)) + assert len(what) >= len(value) - with open(path, 'r+b') as f: + with open(path, "r+b") as f: do_file(f) -if __name__ == '__main__': +if __name__ == "__main__": main() # TODO: diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py index 8848d22..667be61 100644 --- a/tests/test_cmdline.py +++ b/tests/test_cmdline.py @@ -1,26 +1,22 @@ -import sys import subprocess -import virtualenv +import sys + import pytest +import virtualenv + VIRTUALENV_SCRIPT = virtualenv.__file__ + def test_commandline_basic(tmpdir): """Simple command line usage should work""" - subprocess.check_call([ - sys.executable, - VIRTUALENV_SCRIPT, - str(tmpdir.join('venv')) - ]) + subprocess.check_call([sys.executable, VIRTUALENV_SCRIPT, str(tmpdir.join("venv"))]) + 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, VIRTUALENV_SCRIPT, "-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 @@ -30,15 +26,9 @@ def test_commandline_explicit_interp(tmpdir): @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' + if sys.platform == "win32": + fmt = "%s.%s" else: - fmt = 'python%s.%s' + 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')) - ]) - + subprocess.check_call([sys.executable, VIRTUALENV_SCRIPT, "-p", abbrev, str(tmpdir.join("venv"))]) diff --git a/tests/test_virtualenv.py b/tests/test_virtualenv.py index 90b36ac..27f3d10 100644 --- a/tests/test_virtualenv.py +++ b/tests/test_virtualenv.py @@ -1,13 +1,13 @@ -import virtualenv import optparse import os import shutil import sys import tempfile + import pytest -import platform # noqa +from mock import NonCallableMock, call, patch -from mock import call, Mock, NonCallableMock, patch +import virtualenv def test_version(): @@ -16,8 +16,8 @@ def test_version(): class TestGetInstalledPythons: - key_local_machine = 'key-local-machine' - key_current_user = 'key-current-user' + key_local_machine = "key-local-machine" + key_current_user = "key-current-user" @classmethod def mock_virtualenv_winreg(cls, monkeypatch, data): @@ -29,116 +29,110 @@ class TestGetInstalledPythons: def query_value(key, path): installed_version_tags = data.get(key, []) - suffix = '\\InstallPath' + suffix = "\\InstallPath" if path.endswith(suffix): - version_tag = path[:-len(suffix)] + version_tag = path[: -len(suffix)] if version_tag in installed_version_tags: - return '{}-{}-path'.format(key, version_tag) + return "{}-{}-path".format(key, version_tag) raise WindowsError - mock_winreg = NonCallableMock(spec_set=[ - 'HKEY_LOCAL_MACHINE', - 'HKEY_CURRENT_USER', - 'CreateKey', - 'EnumKey', - 'QueryValue', - 'CloseKey']) - mock_winreg.HKEY_LOCAL_MACHINE = 'HKEY_LOCAL_MACHINE' - mock_winreg.HKEY_CURRENT_USER = 'HKEY_CURRENT_USER' - mock_winreg.CreateKey.side_effect = [cls.key_local_machine, - cls.key_current_user] + mock_winreg = NonCallableMock( + spec_set=["HKEY_LOCAL_MACHINE", "HKEY_CURRENT_USER", "CreateKey", "EnumKey", "QueryValue", "CloseKey"] + ) + mock_winreg.HKEY_LOCAL_MACHINE = "HKEY_LOCAL_MACHINE" + mock_winreg.HKEY_CURRENT_USER = "HKEY_CURRENT_USER" + mock_winreg.CreateKey.side_effect = [cls.key_local_machine, cls.key_current_user] 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) + monkeypatch.setattr(virtualenv, "winreg", mock_winreg) return mock_winreg - @pytest.mark.skipif(sys.platform == 'win32', - reason='non-windows specific test') + @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 not hasattr(virtualenv, "winreg") assert virtualenv.get_installed_pythons() == {} - @pytest.mark.skipif(sys.platform != 'win32', - reason='non-windows specific test') + @pytest.mark.skipif(sys.platform != "win32", reason="non-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.5', # 64-bit only - '3.6-32', # 32-bit only - '3.7', '3.7-32', # both 32 & 64-bit with a 64-bit user install - '3.8'), # 64-bit with a 32-bit user install - self.key_current_user: ( - '2.5', - '2.7', - '3.7', - '3.8-32')}) - monkeypatch.setattr(virtualenv, 'join', '{}\\{}'.format) + mock_winreg = self.mock_virtualenv_winreg( + monkeypatch, + { + self.key_local_machine: ( + "2.4", + "2.7", + "3.2", + "3.4", + "3.5", # 64-bit only + "3.6-32", # 32-bit only + "3.7", + "3.7-32", # both 32 & 64-bit with a 64-bit user install + "3.8", + ), # 64-bit with a 32-bit user install + self.key_current_user: ("2.5", "2.7", "3.7", "3.8-32"), + }, + ) + 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.4': self.key_local_machine + '-2.4-path\\python.exe', - '2.5': self.key_current_user + '-2.5-path\\python.exe', - '2.7': self.key_current_user + '-2.7-path\\python.exe', - '3': self.key_local_machine + '-3.8-path\\python.exe', - '3.2': self.key_local_machine + '-3.2-path\\python.exe', - '3.4': self.key_local_machine + '-3.4-path\\python.exe', - '3.5': self.key_local_machine + '-3.5-path\\python.exe', - '3.5-64': self.key_local_machine + '-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 + '-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 + '-3.7-path\\python.exe', - '3.8': self.key_local_machine + '-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 + '-3.8-path\\python.exe'} + "2": self.key_current_user + "-2.7-path\\python.exe", + "2.4": self.key_local_machine + "-2.4-path\\python.exe", + "2.5": self.key_current_user + "-2.5-path\\python.exe", + "2.7": self.key_current_user + "-2.7-path\\python.exe", + "3": self.key_local_machine + "-3.8-path\\python.exe", + "3.2": self.key_local_machine + "-3.2-path\\python.exe", + "3.4": self.key_local_machine + "-3.4-path\\python.exe", + "3.5": self.key_local_machine + "-3.5-path\\python.exe", + "3.5-64": self.key_local_machine + "-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 + "-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 + "-3.7-path\\python.exe", + "3.8": self.key_local_machine + "-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 + "-3.8-path\\python.exe", + } assert mock_winreg.mock_calls == [ - call.CreateKey(mock_winreg.HKEY_LOCAL_MACHINE, - 'Software\\Python\\PythonCore'), + call.CreateKey(mock_winreg.HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore"), call.EnumKey(self.key_local_machine, 0), - call.QueryValue(self.key_local_machine, '2.4\\InstallPath'), + 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.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.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.QueryValue(self.key_local_machine, "3.4\\InstallPath"), call.EnumKey(self.key_local_machine, 4), - call.QueryValue(self.key_local_machine, '3.5\\InstallPath'), + call.QueryValue(self.key_local_machine, "3.5\\InstallPath"), call.EnumKey(self.key_local_machine, 5), - call.QueryValue(self.key_local_machine, '3.6-32\\InstallPath'), + call.QueryValue(self.key_local_machine, "3.6-32\\InstallPath"), call.EnumKey(self.key_local_machine, 6), - call.QueryValue(self.key_local_machine, '3.7\\InstallPath'), + call.QueryValue(self.key_local_machine, "3.7\\InstallPath"), call.EnumKey(self.key_local_machine, 7), - call.QueryValue(self.key_local_machine, '3.7-32\\InstallPath'), + call.QueryValue(self.key_local_machine, "3.7-32\\InstallPath"), call.EnumKey(self.key_local_machine, 8), - call.QueryValue(self.key_local_machine, '3.8\\InstallPath'), + call.QueryValue(self.key_local_machine, "3.8\\InstallPath"), call.EnumKey(self.key_local_machine, 9), call.CloseKey(self.key_local_machine), - call.CreateKey(mock_winreg.HKEY_CURRENT_USER, - 'Software\\Python\\PythonCore'), + call.CreateKey(mock_winreg.HKEY_CURRENT_USER, "Software\\Python\\PythonCore"), call.EnumKey(self.key_current_user, 0), - call.QueryValue(self.key_current_user, '2.5\\InstallPath'), + 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.QueryValue(self.key_current_user, "2.7\\InstallPath"), call.EnumKey(self.key_current_user, 2), - call.QueryValue(self.key_current_user, '3.7\\InstallPath'), + call.QueryValue(self.key_current_user, "3.7\\InstallPath"), call.EnumKey(self.key_current_user, 3), - call.QueryValue(self.key_current_user, '3.8-32\\InstallPath'), + call.QueryValue(self.key_current_user, "3.8-32\\InstallPath"), call.EnumKey(self.key_current_user, 4), - call.CloseKey(self.key_current_user)] + call.CloseKey(self.key_current_user), + ] - @pytest.mark.skipif(sys.platform != 'win32', - reason='windows specific test') + @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, {}) @@ -147,37 +141,34 @@ class TestGetInstalledPythons: assert installed_pythons == {} assert mock_winreg.mock_calls == [ - call.CreateKey(mock_winreg.HKEY_LOCAL_MACHINE, - 'Software\\Python\\PythonCore'), + call.CreateKey(mock_winreg.HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore"), call.EnumKey(self.key_local_machine, 0), call.CloseKey(self.key_local_machine), - call.CreateKey(mock_winreg.HKEY_CURRENT_USER, - 'Software\\Python\\PythonCore'), + call.CreateKey(mock_winreg.HKEY_CURRENT_USER, "Software\\Python\\PythonCore"), call.EnumKey(self.key_current_user, 0), - call.CloseKey(self.key_current_user)] - - -@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'} + call.CloseKey(self.key_current_user), + ] + + +@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') + exe = virtualenv.resolve_interpreter("foo") - assert exe == test_found_path, \ - "installed python should be accessible by key" + 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) @@ -186,11 +177,10 @@ def test_resolve_interpreter_with_installed_python(mock_abspath, mock_exists, 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): +@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""" test_abs_path = os.path.abspath("/usr/bin/python53") @@ -202,10 +192,9 @@ def test_resolve_interpreter_with_absolute_path( mock_is_executable.assert_called_with(test_abs_path) -@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): +@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""" with pytest.raises(SystemExit): virtualenv.resolve_interpreter("/usr/bin/python53") @@ -213,10 +202,9 @@ def test_resolve_interpreter_with_nonexistent_interpreter( mock_exists.assert_called_with("/usr/bin/python53") -@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): +@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""" invalid = os.path.abspath("/usr/bin/pyt_hon53") @@ -230,68 +218,67 @@ def test_resolve_interpreter_with_invalid_interpreter(mock_exists, 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!")' + "#!/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", + "", + "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!")', ] 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'] + 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 finally: shutil.rmtree(tmp_virtualenv) @@ -300,14 +287,16 @@ 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) @@ -1,6 +1,6 @@ [tox] minversion = 3.3.0 -envlist = embed, py{27,34,35,36,37}, pypy{,3}, cross_python{2,3}, docs, package_readme +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 @@ -91,3 +91,29 @@ skip_install = true deps = commands = python {toxinidir}/bin/rebuild-script.py +[testenv:fix_lint] +description = format the code base to adhere to our styles, and complain about what we cannot do automatically +basepython = python3.7 +passenv = HOMEPATH PROGRAMDATA http_proxy https_proxy no_proxy +deps = pre-commit == 1.12.0 +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 = __builtin__,_winreg,mock,pytest,sets,setuptools,sitecustomize,sphinx_rtd_theme,urlparse,usercustomize,winreg + +[flake8] +max-complexity = 22 +max-line-length = 120 +ignore = E203, W503, C901, E402 +exclude = virtualenv_embedded/site.py + +[pep8] +max-line-length = 120 diff --git a/virtualenv_embedded/activate.csh b/virtualenv_embedded/activate.csh index 864865b..2355e77 100644 --- a/virtualenv_embedded/activate.csh +++ b/virtualenv_embedded/activate.csh @@ -33,4 +33,3 @@ unset env_name alias pydoc python -m pydoc rehash - diff --git a/virtualenv_embedded/activate_this.py b/virtualenv_embedded/activate_this.py index f18193b..444d3fd 100644 --- a/virtualenv_embedded/activate_this.py +++ b/virtualenv_embedded/activate_this.py @@ -9,19 +9,21 @@ 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 + "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))" + ) import os +import site +import sys -old_os_path = os.environ.get('PATH', '') -os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path +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') +if sys.platform == "win32": + site_packages = os.path.join(base, "Lib", "site-packages") else: - site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') + site_packages = os.path.join(base, "lib", "python%s" % sys.version[:3], "site-packages") prev_sys_path = list(sys.path) -import site + site.addsitedir(site_packages) sys.real_prefix = sys.prefix sys.prefix = base diff --git a/virtualenv_embedded/deactivate.bat b/virtualenv_embedded/deactivate.bat index 74d3671..5ad81d4 100644 --- a/virtualenv_embedded/deactivate.bat +++ b/virtualenv_embedded/deactivate.bat @@ -16,4 +16,5 @@ 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
\ No newline at end of file +:ENDIFVPATH + diff --git a/virtualenv_embedded/distutils-init.py b/virtualenv_embedded/distutils-init.py index 29fc1da..59f55f1 100644 --- a/virtualenv_embedded/distutils-init.py +++ b/virtualenv_embedded/distutils-init.py @@ -1,20 +1,21 @@ +import imp 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 + real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ("", "", imp.PKG_DIRECTORY)) # Copy the relevant attributes try: __revision__ = real_distutils.__revision__ @@ -22,80 +23,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 diff --git a/virtualenv_embedded/site.py b/virtualenv_embedded/site.py index 7969769..663e985 100644 --- a/virtualenv_embedded/site.py +++ b/virtualenv_embedded/site.py @@ -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,34 @@ 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' +_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) + def makepath(*paths): dir = os.path.join(*paths) - if _is_jython and (dir == '__classpath__' or - dir.startswith('__pyclasspath__')): + 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__')): + 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 +130,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.{}-{:.3}".format(get_platform(), sys.version) + 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 +157,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'""" @@ -183,6 +189,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 +200,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 +213,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 +222,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") or _is_jython: 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", sys.version[:3], "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" + sys.version[:3], "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")] + 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]): + 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 +255,32 @@ 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" + sys.version[:3], "dist-packages")) + if sys.version[0] == "2": + sitedirs.append(os.path.join(prefix, "lib", "python" + sys.version[:3], "dist-packages")) else: - sitedirs.append(os.path.join(prefix, "lib", - "python" + sys.version[0], - "dist-packages")) + sitedirs.append(os.path.join(prefix, "lib", "python" + sys.version[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: + home = os.environ.get("HOME") if home: - sitedirs.append( - os.path.join(home, - 'Library', - 'Python', - sys.version[:3], - 'site-packages')) + sitedirs.append(os.path.join(home, "Library", "Python", sys.version[:3], "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 +291,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 +305,7 @@ def check_enableusersite(): return True + def addusersitepackages(known_paths): """Add a per user site-package to sys.path @@ -324,7 +324,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 +334,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" + sys.version[0] + sys.version[2], "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" + sys.version[:3], "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" + sys.version[:3], "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 +361,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 +374,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 +396,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): @@ -436,7 +432,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 +440,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 +460,33 @@ 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).") + 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/") + else: builtins.credits = _Printer( "credits", - "PyPy is maintained by the PyPy developers: http://pypy.org/") - else: - 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 http://www.python.org/%.3s/license.html" % sys.version, ["LICENSE.txt", "LICENSE"], - [os.path.join(here, os.pardir), here, os.curdir]) + [os.path.join(here, os.pardir), here, os.curdir], + ) class _Helper(object): @@ -498,38 +496,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 +544,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 +554,40 @@ 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')] + paths = [os.path.join(sys.real_prefix, "Lib")] elif _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" + 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]) if os.path.exists(lib64_path): if _is_64bit: paths.insert(0, lib64_path) @@ -595,28 +599,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" + sys.version[:3], "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 +628,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,16 +638,18 @@ 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. @@ -650,13 +657,14 @@ def fixclasspath(): paths = [] classpaths = [] for path in sys.path: - if path == '__classpath__' or path.startswith('__pyclasspath__'): + 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.""" try: @@ -670,12 +678,11 @@ def main(): virtual_install_main_packages() 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,7 +691,7 @@ 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() @@ -700,8 +707,10 @@ def main(): if hasattr(sys, "setdefaultencoding"): del sys.setdefaultencoding + main() + def _script(): help = """\ %s [--user-base] [--user-site] @@ -721,22 +730,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_BASE))) + 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 +762,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() |