Skip to content

Commit

Permalink
Fix brew cannot copy (#2640)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborbernat committed Sep 7, 2023
1 parent 41132db commit 1b75a42
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 34 deletions.
25 changes: 14 additions & 11 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ jobs:
- macos-latest
- windows-latest
include:
- { os: macos-latest, py: "brew@3.11" }
- { os: macos-latest, py: "brew@3.10" }
- { os: macos-latest, py: "brew@3.9" }
- { os: macos-latest, py: "brew@3.8" }
steps:
Expand All @@ -55,22 +57,21 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install tox
run: python -m pip install tox pip -U
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Use local virtualenv for tox
run: python -m pip install .
- name: Setup brew python for test ${{ matrix.py }}
if: startsWith(matrix.py,'brew@')
run: |
set -e
PY=$(echo '${{ matrix.py }}' | cut -c 6-)
brew upgrade python@$PY || brew install python@$PY
brew doctor # Fix dyld library not loaded issues
brew cleanup && brew upgrade python@$PY || brew install python@$PY
echo "/usr/local/opt/python@$PY/libexec/bin" >>"${GITHUB_PATH}"
shell: bash
- name: Install tox
run: python -m pip install tox pip -U
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Use local virtualenv for tox
run: python -m pip install .
- name: Setup python for test ${{ matrix.py }}
if: "!( startsWith(matrix.py,'brew@') || endsWith(matrix.py, '-dev') )"
uses: actions/setup-python@v4
Expand All @@ -85,7 +86,7 @@ jobs:
file_handler.write(env)
shell: python
- name: Setup test suite
run: tox -vv --notest
run: tox -vv --notest --skip-missing-interpreters false
- name: Run test suite
run: tox --skip-pkg-install
env:
Expand Down Expand Up @@ -122,7 +123,9 @@ jobs:
python-version: "3.11"
- name: Install tox
run: python -m pip install tox
- name: Setup check
run: python -m tox --skip-missing-interpreters false -e ${{ matrix.tox_env }} --notest
- name: Run check for ${{ matrix.tox_env }}
run: python -m tox -e ${{ matrix.tox_env }}
run: python -m tox --skip-pkg-install -e ${{ matrix.tox_env }}
env:
UPGRADE_ADVISORY: "yes"
1 change: 1 addition & 0 deletions docs/changelog/2640.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Brew on macOS no longer allows copy builds - disallow choosing this by :user:`gaborbernat`.
36 changes: 17 additions & 19 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Installation
via pipx
--------

:pypi:`virtualenv` is a CLI tool that needs a Python interpreter to run. If you already have a ``Python 3.5+``
:pypi:`virtualenv` is a CLI tool that needs a Python interpreter to run. If you already have a ``Python 3.7+``
interpreter the best is to use :pypi:`pipx` to install virtualenv into an isolated environment. This has the added
benefit that later you'll be able to upgrade virtualenv without affecting other parts of the system.

Expand Down Expand Up @@ -58,11 +58,14 @@ with a python interpreter:
The root level zipapp is always the current latest release. To get the last supported zipapp against a given python
minor release use the link ``https://bootstrap.pypa.io/virtualenv/x.y/virtualenv.pyz``, e.g. for the last virtualenv
supporting Python 2.7 use
`https://bootstrap.pypa.io/virtualenv/2.7/virtualenv.pyz <https://bootstrap.pypa.io/virtualenv/2.7/virtualenv.pyz>`_.
supporting Python 3.11 use
`https://bootstrap.pypa.io/virtualenv/3.11/virtualenv.pyz <https://bootstrap.pypa.io/virtualenv/3.11/virtualenv.pyz>`_.

If you are looking for past version of virtualenv.pyz they are available here:
https://github.com/pypa/get-virtualenv/blob/<virtualenv version>/public/<python version>/virtualenv.pyz?raw=true

.. code-block:: console
https://github.com/pypa/get-virtualenv/blob/<virtualenv version>/public/<python version>/virtualenv.pyz?raw=true
latest unreleased
-----------------
Expand All @@ -81,18 +84,21 @@ Python and OS Compatibility

virtualenv works with the following Python interpreter implementations:

- `CPython <https://www.python.org/>`_ versions 3.7, 3.8, 3.9, 3.10, 3.11, 3.12
- `PyPy <https://pypy.org/>`_ 3.7, 3.8, 3.9
- `CPython <https://www.python.org/>`_: ``3.12 >= python_version >= 3.7``
- `PyPy <https://pypy.org/>`_: ``3.9 >= python_version >= 3.7``

This means virtualenv works on the latest patch version of each of these minor versions. Previous patch versions are
supported on a best effort approach.

CPython is shipped in multiple forms, and each OS repackages it, often applying some customization along the way.
Therefore we cannot say universally that we support all platforms, but rather specify some we test against. In case
of ones not specified here the support is unknown, though likely will work. If you find some cases please open a feature
request on our issue tracker. Note, as of ``20.18.0`` we no longer support running under Python less than 3.7. Also, as
of ``20.22.0`` we no longer support creating environments for Python 2.7, 3.5 and 3.6.
request on our issue tracker.

Note:

- as of ``20.18.0`` -- ``2023-02-06`` -- we no longer support running under Python ``<=3.6``,
- as of ``20.22.0`` -- ``2023-04-19`` -- we no longer support creating environments for Python ``<=3.6``.

Linux
~~~~~
Expand All @@ -107,19 +113,11 @@ macOS
~~~~~
In case of macOS we support:

- installations from `python.org <https://www.python.org/downloads/>`_
- python versions installed via `brew <https://docs.brew.sh/Homebrew-and-Python>`_ (both older python2.7 and python3)
- Python 3 part of XCode (Python framework - ``/Library/Frameworks/Python3.framework/``)
- Python 2 part of the OS (``/System/Library/Frameworks/Python.framework/Versions/``)
- installations from `python.org <https://www.python.org/downloads/>`_,
- python versions installed via `brew <https://docs.brew.sh/Homebrew-and-Python>`_,
- Python 3 part of XCode (Python framework - ``/Library/Frameworks/Python3.framework/``).

Windows
~~~~~~~
- Installations from `python.org <https://www.python.org/downloads/>`_
- Windows Store Python - note only `version 3.7+ <https://www.microsoft.com/en-us/p/python-38/9mssztt1n39l>`_

Packaging variants
~~~~~~~~~~~~~~~~~~
- Normal variant (file structure as comes from `python.org <https://www.python.org/downloads/>`_).
- We support CPython 2 system installations that do not contain the python files for the standard library if the
respective compiled files are present (e.g. only ``os.pyc``, not ``os.py``). This can be used by custom systems may
want to maximize available storage or obfuscate source code by removing ``.py`` files.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ nushell = "virtualenv.activation.nushell:NushellActivator"
powershell = "virtualenv.activation.powershell:PowerShellActivator"
python = "virtualenv.activation.python:PythonActivator"
[project.entry-points."virtualenv.create"]
cpython3-mac-brew = "virtualenv.create.via_global_ref.builtin.cpython.mac_os:CPython3macOsBrew"
cpython3-mac-framework = "virtualenv.create.via_global_ref.builtin.cpython.mac_os:CPython3macOsFramework"
cpython3-posix = "virtualenv.create.via_global_ref.builtin.cpython.cpython3:CPython3Posix"
cpython3-win = "virtualenv.create.via_global_ref.builtin.cpython.cpython3:CPython3Windows"
Expand Down
2 changes: 1 addition & 1 deletion src/virtualenv/create/via_global_ref/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ def add_parser_arguments(cls, parser, interpreter, meta, app_data):
dest="system_site",
help="give the virtual environment access to the system site-packages dir",
)
group = parser.add_mutually_exclusive_group()
if not meta.can_symlink and not meta.can_copy:
msg = "neither symlink or copy method supported"
raise RuntimeError(msg)
group = parser.add_mutually_exclusive_group()
if meta.can_symlink:
group.add_argument(
"--symlinks",
Expand Down
11 changes: 11 additions & 0 deletions src/virtualenv/create/via_global_ref/builtin/cpython/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import re
from abc import ABCMeta
from collections import OrderedDict
from pathlib import Path
Expand Down Expand Up @@ -54,9 +55,19 @@ def is_mac_os_framework(interpreter):
return False


def is_macos_brew(interpreter):
return interpreter.platform == "darwin" and _BREW.fullmatch(interpreter.system_prefix) is not None


_BREW = re.compile(
r"/(usr/local|opt/homebrew)/(opt/python@3\.\d{1,2}|Cellar/python@3\.\d{1,2}/3\.\d{1,2}\.\d{1,2})/Frameworks/"
r"Python\.framework/Versions/3\.\d{1,2}",
)

__all__ = [
"CPython",
"CPythonPosix",
"CPythonWindows",
"is_mac_os_framework",
"is_macos_brew",
]
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from virtualenv.create.via_global_ref.builtin.ref import PathRefToDest
from virtualenv.create.via_global_ref.store import is_store_python

from .common import CPython, CPythonPosix, CPythonWindows, is_mac_os_framework
from .common import CPython, CPythonPosix, CPythonWindows, is_mac_os_framework, is_macos_brew


class CPython3(CPython, Python3Supports, metaclass=abc.ABCMeta):
Expand All @@ -21,7 +21,11 @@ class CPython3(CPython, Python3Supports, metaclass=abc.ABCMeta):
class CPython3Posix(CPythonPosix, CPython3):
@classmethod
def can_describe(cls, interpreter):
return is_mac_os_framework(interpreter) is False and super().can_describe(interpreter)
return (
is_mac_os_framework(interpreter) is False
and is_macos_brew(interpreter) is False
and super().can_describe(interpreter)
)

def env_patch_text(self):
text = super().env_patch_text()
Expand Down
16 changes: 15 additions & 1 deletion src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
PathRefToDest,
RefMust,
)
from virtualenv.create.via_global_ref.builtin.via_global_self_do import BuiltinViaGlobalRefMeta

from .common import CPython, CPythonPosix, is_mac_os_framework
from .common import CPython, CPythonPosix, is_mac_os_framework, is_macos_brew
from .cpython3 import CPython3


Expand Down Expand Up @@ -258,7 +259,20 @@ def do_file(file, offset=0, size=maxint):
return mach_o_change


class CPython3macOsBrew(CPython3, CPythonPosix):
@classmethod
def can_describe(cls, interpreter):
return is_macos_brew(interpreter) and super().can_describe(interpreter)

@classmethod
def setup_meta(cls, interpreter): # noqa: ARG003
meta = BuiltinViaGlobalRefMeta()
meta.copy_error = "Brew disables copy creation: https://github.com/Homebrew/homebrew-core/issues/138159"
return meta


__all__ = [
"CPythonmacOsFramework",
"CPython3macOsFramework",
"CPython3macOsBrew",
]
3 changes: 3 additions & 0 deletions src/virtualenv/create/via_global_ref/venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from virtualenv.util.subprocess import run_cmd

from .api import ViaGlobalRefApi, ViaGlobalRefMeta
from .builtin.cpython.mac_os import CPython3macOsBrew
from .builtin.pypy.pypy3 import Pypy3Windows


Expand All @@ -27,6 +28,8 @@ def _args(self):
@classmethod
def can_create(cls, interpreter):
if interpreter.has_venv:
if CPython3macOsBrew.can_describe(interpreter):
return CPython3macOsBrew.setup_meta(interpreter)
meta = ViaGlobalRefMeta()
if interpreter.platform == "win32":
meta = handle_store_python(meta, interpreter)
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/config/test_env_var.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from virtualenv.config.cli.parser import VirtualEnvOptions
from virtualenv.config.ini import IniConfig
from virtualenv.create.via_global_ref.builtin.cpython.common import is_macos_brew
from virtualenv.discovery.py_info import PythonInfo
from virtualenv.run import session_via_cli


Expand Down Expand Up @@ -74,6 +76,7 @@ def test_extra_search_dir_via_env_var(tmp_path, monkeypatch):


@pytest.mark.usefixtures("_empty_conf")
@pytest.mark.skipif(is_macos_brew(PythonInfo.current_system()), reason="no copy on brew")
def test_value_alias(monkeypatch, mocker):
from virtualenv.config.cli.parser import VirtualEnvConfigParser

Expand Down
2 changes: 2 additions & 0 deletions tests/unit/create/test_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from virtualenv.__main__ import run, run_with_catch
from virtualenv.create.creator import DEBUG_SCRIPT, Creator, get_env_debug_info
from virtualenv.create.pyenv_cfg import PyEnvCfg
from virtualenv.create.via_global_ref.builtin.cpython.common import is_macos_brew
from virtualenv.create.via_global_ref.builtin.cpython.cpython3 import CPython3Posix
from virtualenv.discovery.py_info import PythonInfo
from virtualenv.info import IS_PYPY, IS_WIN, fs_is_case_sensitive
Expand Down Expand Up @@ -430,6 +431,7 @@ def list_files(path):
return result


@pytest.mark.skipif(is_macos_brew(CURRENT), reason="no copy on brew")
def test_zip_importer_can_import_setuptools(tmp_path):
"""We're patching the loaders so might fail on r/o loaders, such as zipimporter on CPython<3.8"""
result = cli_run(
Expand Down

0 comments on commit 1b75a42

Please sign in to comment.