Compare commits
No commits in common. 'epel9' and 'c8-beta-stream-3.6' have entirely different histories.
epel9
...
c8-beta-st
@ -1,4 +1 @@
|
||||
/virtualenv-*.tar.gz
|
||||
/virtualenv-*/
|
||||
/results_python-virtualenv/
|
||||
*.rpm
|
||||
SOURCES/virtualenv-15.1.0.tar.gz
|
||||
|
@ -0,0 +1 @@
|
||||
995ce0fa007210ac2f10258999d06813ecdd6eeb SOURCES/virtualenv-15.1.0.tar.gz
|
@ -1,339 +0,0 @@
|
||||
From 42e0698087f061d1d7db6fcb9469302bda5d44ca Mon Sep 17 00:00:00 2001
|
||||
From: chrysle <fritzihab@posteo.de>
|
||||
Date: Fri, 28 Apr 2023 01:36:03 +0200
|
||||
Subject: [PATCH] 3.12 support and no setuptools/wheel on 3.12+ (#2558)
|
||||
|
||||
Cherry-picked from fd93dd79be89b21e6e9d43ca2dd1b02b811f6d6f
|
||||
---
|
||||
docs/changelog/2487.feature.rst | 6 +++++
|
||||
docs/changelog/2558.feature.rst | 1 +
|
||||
docs/render_cli.py | 10 +------
|
||||
docs/user_guide.rst | 5 ++--
|
||||
src/virtualenv/activation/python/__init__.py | 3 ++-
|
||||
src/virtualenv/seed/embed/base_embed.py | 11 +++++---
|
||||
src/virtualenv/util/path/_sync.py | 4 ++-
|
||||
tests/unit/config/test___main__.py | 2 +-
|
||||
tests/unit/create/test_creator.py | 26 ++++++++++++++++---
|
||||
tests/unit/discovery/py_info/test_py_info.py | 2 +-
|
||||
tests/unit/discovery/windows/conftest.py | 2 +-
|
||||
tests/unit/seed/embed/test_base_embed.py | 12 +++++++++
|
||||
.../embed/test_bootstrap_link_via_app_data.py | 4 +--
|
||||
.../unit/seed/wheels/test_periodic_update.py | 17 ++++++++++--
|
||||
14 files changed, 79 insertions(+), 26 deletions(-)
|
||||
create mode 100644 docs/changelog/2487.feature.rst
|
||||
create mode 100644 docs/changelog/2558.feature.rst
|
||||
|
||||
diff --git a/docs/changelog/2487.feature.rst b/docs/changelog/2487.feature.rst
|
||||
new file mode 100644
|
||||
index 0000000..12cc896
|
||||
--- /dev/null
|
||||
+++ b/docs/changelog/2487.feature.rst
|
||||
@@ -0,0 +1,6 @@
|
||||
+Do not install ``wheel`` and ``setuptools`` seed packages for Python 3.12+. To restore the old behaviour use:
|
||||
+
|
||||
+- for ``wheel`` use ``VIRTUALENV_WHEEL=bundle`` environment variable or ``--wheel=bundle`` CLI flag,
|
||||
+- for ``setuptools`` use ``VIRTUALENV_SETUPTOOLS=bundle`` environment variable or ``--setuptools=bundle`` CLI flag.
|
||||
+
|
||||
+By :user:`chrysle`.
|
||||
diff --git a/docs/changelog/2558.feature.rst b/docs/changelog/2558.feature.rst
|
||||
new file mode 100644
|
||||
index 0000000..58b627a
|
||||
--- /dev/null
|
||||
+++ b/docs/changelog/2558.feature.rst
|
||||
@@ -0,0 +1 @@
|
||||
+3.12 support - by :user:`gaborbernat`.
|
||||
diff --git a/src/virtualenv/activation/python/__init__.py b/src/virtualenv/activation/python/__init__.py
|
||||
index eb83504..a49444b 100644
|
||||
--- a/src/virtualenv/activation/python/__init__.py
|
||||
+++ b/src/virtualenv/activation/python/__init__.py
|
||||
@@ -12,10 +12,11 @@ class PythonActivator(ViaTemplateActivator):
|
||||
def replacements(self, creator, dest_folder):
|
||||
replacements = super().replacements(creator, dest_folder)
|
||||
lib_folders = OrderedDict((os.path.relpath(str(i), str(dest_folder)), None) for i in creator.libs)
|
||||
+ lib_folders = os.pathsep.join(lib_folders.keys()).replace("\\", "\\\\") # escape Windows path characters
|
||||
win_py2 = creator.interpreter.platform == "win32" and creator.interpreter.version_info.major == 2
|
||||
replacements.update(
|
||||
{
|
||||
- "__LIB_FOLDERS__": os.pathsep.join(lib_folders.keys()),
|
||||
+ "__LIB_FOLDERS__": lib_folders,
|
||||
"__DECODE_PATH__": ("yes" if win_py2 else ""),
|
||||
},
|
||||
)
|
||||
diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py
|
||||
index f29110b..6782d6f 100644
|
||||
--- a/src/virtualenv/seed/embed/base_embed.py
|
||||
+++ b/src/virtualenv/seed/embed/base_embed.py
|
||||
@@ -39,7 +39,7 @@ class BaseEmbed(Seeder, metaclass=ABCMeta):
|
||||
return {
|
||||
distribution: getattr(self, f"{distribution}_version")
|
||||
for distribution in self.distributions()
|
||||
- if getattr(self, f"no_{distribution}") is False
|
||||
+ if getattr(self, f"no_{distribution}") is False and getattr(self, f"{distribution}_version") != "none"
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@@ -69,11 +69,13 @@ class BaseEmbed(Seeder, metaclass=ABCMeta):
|
||||
default=[],
|
||||
)
|
||||
for distribution, default in cls.distributions().items():
|
||||
+ if interpreter.version_info[:2] >= (3, 12) and distribution in {"wheel", "setuptools"}:
|
||||
+ default = "none"
|
||||
parser.add_argument(
|
||||
f"--{distribution}",
|
||||
dest=distribution,
|
||||
metavar="version",
|
||||
- help=f"version of {distribution} to install as seed: embed, bundle or exact version",
|
||||
+ help=f"version of {distribution} to install as seed: embed, bundle, none or exact version",
|
||||
default=default,
|
||||
)
|
||||
for distribution in cls.distributions():
|
||||
@@ -101,7 +103,10 @@ class BaseEmbed(Seeder, metaclass=ABCMeta):
|
||||
for distribution in self.distributions():
|
||||
if getattr(self, f"no_{distribution}"):
|
||||
continue
|
||||
- ver = f"={getattr(self, f'{distribution}_version', None) or 'latest'}"
|
||||
+ version = getattr(self, f"{distribution}_version", None)
|
||||
+ if version == "none":
|
||||
+ continue
|
||||
+ ver = f"={version or 'latest'}"
|
||||
result += f" {distribution}{ver},"
|
||||
return result[:-1] + ")"
|
||||
|
||||
diff --git a/src/virtualenv/util/path/_sync.py b/src/virtualenv/util/path/_sync.py
|
||||
index 604379d..b0af1eb 100644
|
||||
--- a/src/virtualenv/util/path/_sync.py
|
||||
+++ b/src/virtualenv/util/path/_sync.py
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
+import sys
|
||||
from stat import S_IWUSR
|
||||
|
||||
|
||||
@@ -56,7 +57,8 @@ def safe_delete(dest):
|
||||
else:
|
||||
raise
|
||||
|
||||
- shutil.rmtree(str(dest), ignore_errors=True, onerror=onerror)
|
||||
+ kwargs = {"onexc" if sys.version_info >= (3, 12) else "onerror": onerror}
|
||||
+ shutil.rmtree(str(dest), ignore_errors=True, **kwargs)
|
||||
|
||||
|
||||
class _Debug:
|
||||
diff --git a/tests/unit/config/test___main__.py b/tests/unit/config/test___main__.py
|
||||
index 62228c9..d22ef7e 100644
|
||||
--- a/tests/unit/config/test___main__.py
|
||||
+++ b/tests/unit/config/test___main__.py
|
||||
@@ -58,7 +58,7 @@ def test_fail_with_traceback(raise_on_session_done, tmp_path, capsys):
|
||||
|
||||
@pytest.mark.usefixtures("session_app_data")
|
||||
def test_session_report_full(tmp_path, capsys):
|
||||
- run_with_catch([str(tmp_path)])
|
||||
+ run_with_catch([str(tmp_path), "--setuptools", "bundle", "--wheel", "bundle"])
|
||||
out, err = capsys.readouterr()
|
||||
assert err == ""
|
||||
lines = out.splitlines()
|
||||
diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py
|
||||
index 0ec6d62..8b9d688 100644
|
||||
--- a/tests/unit/create/test_creator.py
|
||||
+++ b/tests/unit/create/test_creator.py
|
||||
@@ -412,7 +412,19 @@ def test_create_long_path(tmp_path):
|
||||
@pytest.mark.parametrize("creator", sorted(set(PythonInfo.current_system().creators().key_to_class) - {"builtin"}))
|
||||
@pytest.mark.usefixtures("session_app_data")
|
||||
def test_create_distutils_cfg(creator, tmp_path, monkeypatch):
|
||||
- result = cli_run([str(tmp_path / "venv"), "--activators", "", "--creator", creator])
|
||||
+ result = cli_run(
|
||||
+ [
|
||||
+ str(tmp_path / "venv"),
|
||||
+ "--activators",
|
||||
+ "",
|
||||
+ "--creator",
|
||||
+ creator,
|
||||
+ "--setuptools",
|
||||
+ "bundle",
|
||||
+ "--wheel",
|
||||
+ "bundle",
|
||||
+ ],
|
||||
+ )
|
||||
|
||||
app = Path(__file__).parent / "console_app"
|
||||
dest = tmp_path / "console_app"
|
||||
@@ -465,7 +477,9 @@ def list_files(path):
|
||||
|
||||
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([str(tmp_path / "venv"), "--activators", "", "--no-pip", "--no-wheel", "--copies"])
|
||||
+ result = cli_run(
|
||||
+ [str(tmp_path / "venv"), "--activators", "", "--no-pip", "--no-wheel", "--copies", "--setuptools", "bundle"],
|
||||
+ )
|
||||
zip_path = tmp_path / "site-packages.zip"
|
||||
with zipfile.ZipFile(str(zip_path), "w", zipfile.ZIP_DEFLATED) as zip_handler:
|
||||
lib = str(result.creator.purelib)
|
||||
@@ -499,6 +513,7 @@ def test_no_preimport_threading(tmp_path):
|
||||
out = subprocess.check_output(
|
||||
[str(session.creator.exe), "-c", r"import sys; print('\n'.join(sorted(sys.modules)))"],
|
||||
text=True,
|
||||
+ encoding="utf-8",
|
||||
)
|
||||
imported = set(out.splitlines())
|
||||
assert "threading" not in imported
|
||||
@@ -515,6 +530,7 @@ def test_pth_in_site_vs_python_path(tmp_path):
|
||||
out = subprocess.check_output(
|
||||
[str(session.creator.exe), "-c", r"import sys; print(sys.testpth)"],
|
||||
text=True,
|
||||
+ encoding="utf-8",
|
||||
)
|
||||
assert out == "ok\n"
|
||||
# same with $PYTHONPATH pointing to site_packages
|
||||
@@ -527,6 +543,7 @@ def test_pth_in_site_vs_python_path(tmp_path):
|
||||
[str(session.creator.exe), "-c", r"import sys; print(sys.testpth)"],
|
||||
text=True,
|
||||
env=env,
|
||||
+ encoding="utf-8",
|
||||
)
|
||||
assert out == "ok\n"
|
||||
|
||||
@@ -540,6 +557,7 @@ def test_getsitepackages_system_site(tmp_path):
|
||||
out = subprocess.check_output(
|
||||
[str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"],
|
||||
text=True,
|
||||
+ encoding="utf-8",
|
||||
)
|
||||
site_packages = ast.literal_eval(out)
|
||||
|
||||
@@ -554,6 +572,7 @@ def test_getsitepackages_system_site(tmp_path):
|
||||
out = subprocess.check_output(
|
||||
[str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"],
|
||||
text=True,
|
||||
+ encoding="utf-8",
|
||||
)
|
||||
site_packages = [str(Path(i).resolve()) for i in ast.literal_eval(out)]
|
||||
|
||||
@@ -579,6 +598,7 @@ def test_get_site_packages(tmp_path):
|
||||
out = subprocess.check_output(
|
||||
[str(session.creator.exe), "-c", r"import site; print(site.getsitepackages())"],
|
||||
text=True,
|
||||
+ encoding="utf-8",
|
||||
)
|
||||
site_packages = ast.literal_eval(out)
|
||||
|
||||
@@ -617,7 +637,7 @@ def test_python_path(monkeypatch, tmp_path, python_path_on):
|
||||
if flag:
|
||||
cmd.append(flag)
|
||||
cmd.extend(["-c", "import json; import sys; print(json.dumps(sys.path))"])
|
||||
- return [i if case_sensitive else i.lower() for i in json.loads(subprocess.check_output(cmd))]
|
||||
+ return [i if case_sensitive else i.lower() for i in json.loads(subprocess.check_output(cmd, encoding="utf-8"))]
|
||||
|
||||
monkeypatch.delenv("PYTHONPATH", raising=False)
|
||||
base = _get_sys_path()
|
||||
diff --git a/tests/unit/discovery/py_info/test_py_info.py b/tests/unit/discovery/py_info/test_py_info.py
|
||||
index 24b129c..f3fdb7e 100644
|
||||
--- a/tests/unit/discovery/py_info/test_py_info.py
|
||||
+++ b/tests/unit/discovery/py_info/test_py_info.py
|
||||
@@ -289,7 +289,7 @@ def test_discover_exe_on_path_non_spec_name_not_match(mocker):
|
||||
assert CURRENT.satisfies(spec, impl_must_match=True) is False
|
||||
|
||||
|
||||
-@pytest.mark.skipif(IS_PYPY, reason="setuptools distutil1s patching does not work")
|
||||
+@pytest.mark.skipif(IS_PYPY, reason="setuptools distutils patching does not work")
|
||||
def test_py_info_setuptools():
|
||||
from setuptools.dist import Distribution
|
||||
|
||||
diff --git a/tests/unit/discovery/windows/conftest.py b/tests/unit/discovery/windows/conftest.py
|
||||
index 58da626..94f14da 100644
|
||||
--- a/tests/unit/discovery/windows/conftest.py
|
||||
+++ b/tests/unit/discovery/windows/conftest.py
|
||||
@@ -9,7 +9,7 @@ def _mock_registry(mocker):
|
||||
from virtualenv.discovery.windows.pep514 import winreg
|
||||
|
||||
loc, glob = {}, {}
|
||||
- mock_value_str = (Path(__file__).parent / "winreg-mock-values.py").read_text()
|
||||
+ mock_value_str = (Path(__file__).parent / "winreg-mock-values.py").read_text(encoding="utf-8")
|
||||
exec(mock_value_str, glob, loc)
|
||||
enum_collect = loc["enum_collect"]
|
||||
value_collect = loc["value_collect"]
|
||||
diff --git a/tests/unit/seed/embed/test_base_embed.py b/tests/unit/seed/embed/test_base_embed.py
|
||||
index 3344c74..ef2f829 100644
|
||||
--- a/tests/unit/seed/embed/test_base_embed.py
|
||||
+++ b/tests/unit/seed/embed/test_base_embed.py
|
||||
@@ -1,3 +1,5 @@
|
||||
+import sys
|
||||
+
|
||||
import pytest
|
||||
|
||||
from virtualenv.run import session_via_cli
|
||||
@@ -10,3 +12,13 @@ from virtualenv.run import session_via_cli
|
||||
def test_download_cli_flag(args, download, tmp_path):
|
||||
session = session_via_cli(args + [str(tmp_path)])
|
||||
assert session.seeder.download is download
|
||||
+
|
||||
+
|
||||
+def test_embed_wheel_versions(tmp_path):
|
||||
+ session = session_via_cli([str(tmp_path)])
|
||||
+ expected = (
|
||||
+ {"pip": "bundle"}
|
||||
+ if sys.version_info[:2] >= (3, 12)
|
||||
+ else {"pip": "bundle", "setuptools": "bundle", "wheel": "bundle"}
|
||||
+ )
|
||||
+ assert session.seeder.distribution_to_versions() == expected
|
||||
diff --git a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py
|
||||
index 2c8c3e8..015686d 100644
|
||||
--- a/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py
|
||||
+++ b/tests/unit/seed/embed/test_bootstrap_link_via_app_data.py
|
||||
@@ -203,7 +203,7 @@ def test_populated_read_only_cache_and_copied_app_data(tmp_path, current_fastest
|
||||
@pytest.mark.parametrize("pkg", ["pip", "setuptools", "wheel"])
|
||||
@pytest.mark.usefixtures("session_app_data", "current_fastest", "coverage_env")
|
||||
def test_base_bootstrap_link_via_app_data_no(tmp_path, pkg):
|
||||
- create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}"]
|
||||
+ create_cmd = [str(tmp_path), "--seeder", "app-data", f"--no-{pkg}", "--wheel", "bundle", "--setuptools", "bundle"]
|
||||
result = cli_run(create_cmd)
|
||||
assert not (result.creator.purelib / pkg).exists()
|
||||
for key in {"pip", "setuptools", "wheel"} - {pkg}:
|
||||
@@ -231,7 +231,7 @@ def _run_parallel_threads(tmp_path):
|
||||
|
||||
def _run(name):
|
||||
try:
|
||||
- cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-pip", "--no-setuptools"])
|
||||
+ cli_run(["--seeder", "app-data", str(tmp_path / name), "--no-pip", "--no-setuptools", "--wheel", "bundle"])
|
||||
except Exception as exception:
|
||||
as_str = str(exception)
|
||||
exceptions.append(as_str)
|
||||
diff --git a/tests/unit/seed/wheels/test_periodic_update.py b/tests/unit/seed/wheels/test_periodic_update.py
|
||||
index e7794f5..c36a983 100644
|
||||
--- a/tests/unit/seed/wheels/test_periodic_update.py
|
||||
+++ b/tests/unit/seed/wheels/test_periodic_update.py
|
||||
@@ -66,7 +66,7 @@ def test_manual_upgrade(session_app_data, caplog, mocker, for_py_version):
|
||||
|
||||
@pytest.mark.usefixtures("session_app_data")
|
||||
def test_pick_periodic_update(tmp_path, mocker, for_py_version):
|
||||
- embed, current = get_embed_wheel("setuptools", "3.5"), get_embed_wheel("setuptools", for_py_version)
|
||||
+ embed, current = get_embed_wheel("setuptools", "3.6"), get_embed_wheel("setuptools", for_py_version)
|
||||
mocker.patch("virtualenv.seed.wheels.bundle.load_embed_wheel", return_value=embed)
|
||||
completed = datetime.now() - timedelta(days=29)
|
||||
u_log = UpdateLog(
|
||||
@@ -77,7 +77,20 @@ def test_pick_periodic_update(tmp_path, mocker, for_py_version):
|
||||
)
|
||||
read_dict = mocker.patch("virtualenv.app_data.via_disk_folder.JSONStoreDisk.read", return_value=u_log.to_dict())
|
||||
|
||||
- result = cli_run([str(tmp_path), "--activators", "", "--no-periodic-update", "--no-wheel", "--no-pip"])
|
||||
+ result = cli_run(
|
||||
+ [
|
||||
+ str(tmp_path),
|
||||
+ "--activators",
|
||||
+ "",
|
||||
+ "--no-periodic-update",
|
||||
+ "--no-wheel",
|
||||
+ "--no-pip",
|
||||
+ "--setuptools",
|
||||
+ "bundle",
|
||||
+ "--wheel",
|
||||
+ "bundle",
|
||||
+ ],
|
||||
+ )
|
||||
|
||||
assert read_dict.call_count == 1
|
||||
installed = [i.name for i in result.creator.purelib.iterdir() if i.suffix == ".dist-info"]
|
||||
--
|
||||
2.40.0
|
||||
|
@ -0,0 +1,16 @@
|
||||
diff --git a/virtualenv.py b/virtualenv.py
|
||||
index c4e3bd5..89b8863 100755
|
||||
--- a/virtualenv.py
|
||||
+++ b/virtualenv.py
|
||||
@@ -1181,8 +1181,9 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
|
||||
exec_dir = join(sys.exec_prefix, 'Lib')
|
||||
else:
|
||||
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 os.path.isdir(exec_dir):
|
||||
+ 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
|
@ -0,0 +1,102 @@
|
||||
diff --git a/tests/test_virtualenv.py b/tests/test_virtualenv.py
|
||||
index ce45ede..7946a16 100644
|
||||
--- a/tests/test_virtualenv.py
|
||||
+++ b/tests/test_virtualenv.py
|
||||
@@ -4,11 +4,16 @@ import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
+import zipfile
|
||||
import pytest
|
||||
import platform # noqa
|
||||
|
||||
from mock import patch, Mock
|
||||
|
||||
+try:
|
||||
+ from pathlib import Path
|
||||
+except ImportError:
|
||||
+ from pathlib2 import Path
|
||||
|
||||
def test_version():
|
||||
"""Should have a version string"""
|
||||
@@ -139,3 +144,44 @@ def test_always_copy_option():
|
||||
" symlink (to %s)" % (full_name, os.readlink(full_name))
|
||||
finally:
|
||||
shutil.rmtree(tmp_virtualenv)
|
||||
+
|
||||
+
|
||||
+def test_missing_certifi_pem(tmp_path):
|
||||
+ """Make sure that we can still create virtual environment if pip is
|
||||
+ patched to not use certifi's cacert.pem and the file is removed.
|
||||
+ This can happen if pip is packaged by Linux distributions."""
|
||||
+ proj_dir = Path(__file__).parent.parent
|
||||
+ support_original = proj_dir / "virtualenv_support"
|
||||
+ pip_wheel = sorted(support_original.glob("pip*whl"))[0]
|
||||
+ whl_name = pip_wheel.name
|
||||
+
|
||||
+ wheeldir = tmp_path / "wheels"
|
||||
+ wheeldir.mkdir()
|
||||
+ tmpcert = tmp_path / "tmpcert.pem"
|
||||
+ cacert = "pip/_vendor/requests/cacert.pem"
|
||||
+ certifi = "pip/_vendor/requests/certs.py"
|
||||
+ oldpath = b"os.path.join(os.path.dirname(__file__), 'cacert.pem')"
|
||||
+ newpath = "r'{}'".format(tmpcert).encode()
|
||||
+ removed = False
|
||||
+ replaced = False
|
||||
+
|
||||
+ with zipfile.ZipFile(str(pip_wheel), "r") as whlin:
|
||||
+ with zipfile.ZipFile(str(wheeldir / whl_name), "w") as whlout:
|
||||
+ for item in whlin.infolist():
|
||||
+ buff = whlin.read(item.filename)
|
||||
+ if item.filename == cacert:
|
||||
+ tmpcert.write_bytes(buff)
|
||||
+ removed = True
|
||||
+ continue
|
||||
+ if item.filename == certifi:
|
||||
+ nbuff = buff.replace(oldpath, newpath)
|
||||
+ assert nbuff != buff
|
||||
+ buff = nbuff
|
||||
+ replaced = True
|
||||
+ whlout.writestr(item, buff)
|
||||
+
|
||||
+ assert removed and replaced
|
||||
+
|
||||
+ venvdir = tmp_path / "venv"
|
||||
+ search_dirs = [str(wheeldir), str(support_original)]
|
||||
+ virtualenv.create_environment(str(venvdir), search_dirs=search_dirs)
|
||||
diff --git a/virtualenv.egg-info/PKG-INFO b/virtualenv.egg-info/PKG-INFO
|
||||
index 11f5c75..501e81a 100644
|
||||
--- a/virtualenv.egg-info/PKG-INFO
|
||||
+++ b/virtualenv.egg-info/PKG-INFO
|
||||
@@ -1,10 +1,12 @@
|
||||
-Metadata-Version: 1.1
|
||||
+Metadata-Version: 1.2
|
||||
Name: virtualenv
|
||||
Version: 15.1.0
|
||||
Summary: Virtual Python Environment builder
|
||||
Home-page: https://virtualenv.pypa.io/
|
||||
-Author: Jannis Leidel, Carl Meyer and Brian Rosner
|
||||
-Author-email: python-virtualenv@groups.google.com
|
||||
+Author: Ian Bicking
|
||||
+Author-email: ianb@colorstudy.com
|
||||
+Maintainer: Jannis Leidel, Carl Meyer and Brian Rosner
|
||||
+Maintainer-email: python-virtualenv@groups.google.com
|
||||
License: MIT
|
||||
Description: Virtualenv
|
||||
==========
|
||||
diff --git a/virtualenv.py b/virtualenv.py
|
||||
index a174b8a..5699998 100755
|
||||
--- a/virtualenv.py
|
||||
+++ b/virtualenv.py
|
||||
@@ -861,7 +861,10 @@ def install_wheel(project_names, py_executable, search_dirs=None,
|
||||
|
||||
import pip
|
||||
|
||||
- cert_data = pkgutil.get_data("pip._vendor.requests", "cacert.pem")
|
||||
+ try:
|
||||
+ cert_data = pkgutil.get_data("pip._vendor.requests", "cacert.pem")
|
||||
+ except IOError:
|
||||
+ cert_data = None
|
||||
if cert_data is not None:
|
||||
cert_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
cert_file.write(cert_data)
|
@ -0,0 +1,230 @@
|
||||
diff --git a/virtualenv.py b/virtualenv.py
|
||||
index 9854324..e5d0883 100755
|
||||
--- a/virtualenv.py
|
||||
+++ b/virtualenv.py
|
||||
@@ -49,7 +49,8 @@ try:
|
||||
except NameError:
|
||||
basestring = str
|
||||
|
||||
-py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
|
||||
+version = '%s.%s' % (sys.version_info[0], sys.version_info[1])
|
||||
+py_version = 'python%s' % version
|
||||
|
||||
is_jython = sys.platform.startswith('java')
|
||||
is_pypy = hasattr(sys, 'pypy_version_info')
|
||||
@@ -1012,13 +1013,13 @@ def change_prefix(filename, dst_prefix):
|
||||
|
||||
if is_darwin:
|
||||
prefixes.extend((
|
||||
- os.path.join("/Library/Python", sys.version[:3], "site-packages"),
|
||||
+ os.path.join("/Library/Python", version, "site-packages"),
|
||||
os.path.join(sys.prefix, "Extras", "lib", "python"),
|
||||
- os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"),
|
||||
+ os.path.join("~", "Library", "Python", version, "site-packages"),
|
||||
# Python 2.6 no-frameworks
|
||||
- os.path.join("~", ".local", "lib","python", sys.version[:3], "site-packages"),
|
||||
+ os.path.join("~", ".local", "lib","python", version, "site-packages"),
|
||||
# System Python 2.7 on OSX Mountain Lion
|
||||
- os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages")))
|
||||
+ os.path.join("~", "Library", "Python", version, "lib", "python", "site-packages")))
|
||||
|
||||
if hasattr(sys, 'real_prefix'):
|
||||
prefixes.append(sys.real_prefix)
|
||||
@@ -1099,7 +1100,7 @@ def copy_required_modules(dst_prefix, symlink):
|
||||
# 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')
|
||||
+ dst_filename = join(dst_prefix, 'lib', py_version, '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
|
||||
@@ -1398,8 +1399,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
|
||||
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_version_major_minor = py_version
|
||||
py_exe_no_version = 'python'
|
||||
required_symlinks = [ py_exe_no_version, py_exe_version_major,
|
||||
py_exe_version_major_minor ]
|
||||
@@ -1547,7 +1547,8 @@ def fix_local_scheme(home_dir, symlink=True):
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
- if sysconfig._get_default_scheme() == 'posix_local':
|
||||
+ get_scheme = getattr(sysconfig, 'get_default_scheme', None) or sysconfig._get_default_scheme
|
||||
+ if get_scheme() == 'posix_local':
|
||||
local_path = os.path.join(home_dir, 'local')
|
||||
if not os.path.exists(local_path):
|
||||
os.mkdir(local_path)
|
||||
@@ -1575,7 +1576,7 @@ def fix_lib64(lib_dir, symlink=True):
|
||||
|
||||
logger.debug('This system uses lib64; symlinking lib64 to lib')
|
||||
|
||||
- assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
|
||||
+ assert os.path.basename(lib_dir) == py_version, (
|
||||
"Unexpected python lib dir: %r" % lib_dir)
|
||||
lib_parent = os.path.dirname(lib_dir)
|
||||
top_level = os.path.dirname(lib_parent)
|
||||
@@ -1637,7 +1638,7 @@ def make_environment_relocatable(home_dir):
|
||||
fixup_pth_and_egg_link(home_dir)
|
||||
## FIXME: need to fix up distutils.cfg
|
||||
|
||||
-OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
|
||||
+OK_ABS_SCRIPTS = ['python', py_version,
|
||||
'activate', 'activate.bat', 'activate_this.py',
|
||||
'activate.fish', 'activate.csh']
|
||||
|
||||
@@ -1647,7 +1648,7 @@ def fixup_scripts(home_dir, bin_dir):
|
||||
'%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', version, '')
|
||||
|
||||
# This is what we expect at the top of scripts:
|
||||
shebang = '#!%s' % os.path.normcase(os.path.join(
|
||||
diff --git a/virtualenv_embedded/activate_this.py b/virtualenv_embedded/activate_this.py
|
||||
index f18193b..8272888 100644
|
||||
--- a/virtualenv_embedded/activate_this.py
|
||||
+++ b/virtualenv_embedded/activate_this.py
|
||||
@@ -19,7 +19,7 @@ base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
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.%s' % (sys.version_info[0], sys.version_info[1]), 'site-packages')
|
||||
prev_sys_path = list(sys.path)
|
||||
import site
|
||||
site.addsitedir(site_packages)
|
||||
diff --git a/virtualenv_embedded/site.py b/virtualenv_embedded/site.py
|
||||
index 7969769..b3603ff 100644
|
||||
--- a/virtualenv_embedded/site.py
|
||||
+++ b/virtualenv_embedded/site.py
|
||||
@@ -134,7 +134,7 @@ 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)
|
||||
+ s = "build/lib.%s-%s.%s" % (get_platform(), sys.version_info[0], sys.version_info[1])
|
||||
if hasattr(sys, 'gettotalrefcount'):
|
||||
s += '-pydebug'
|
||||
s = os.path.join(os.path.dirname(sys.path[-1]), s)
|
||||
@@ -162,7 +162,7 @@ def addpackage(sitedir, name, known_paths):
|
||||
reset = 0
|
||||
fullname = os.path.join(sitedir, name)
|
||||
try:
|
||||
- f = open(fullname, "rU")
|
||||
+ f = open(fullname, "r")
|
||||
except IOError:
|
||||
return
|
||||
try:
|
||||
@@ -222,21 +222,21 @@ def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_pre
|
||||
|
||||
if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python
|
||||
|
||||
- sitedirs = [os.path.join("/Library/Python", sys.version[:3], "site-packages"),
|
||||
+ sitedirs = [os.path.join("/Library/Python", "%s.%s" % (sys.version_info[0], sys.version_info[1]), "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")]
|
||||
+ "python" + "%s.%s" % (sys.version_info[0], sys.version_info[1]), "site-packages")]
|
||||
|
||||
elif os.sep == '/':
|
||||
sitedirs = [os.path.join(prefix,
|
||||
"lib",
|
||||
- "python" + sys.version[:3],
|
||||
+ "python%s.%s" % (sys.version_info[0], sys.version_info[1]),
|
||||
"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")
|
||||
+ os.path.join(prefix, "python%s.%s" % (sys.version_info[0], sys.version_info[1]), "lib-dynload")]
|
||||
+ lib64_dir = os.path.join(prefix, "lib64", "python%s.%s" % (sys.version_info[0], sys.version_info[1]), "site-packages")
|
||||
if (os.path.exists(lib64_dir) and
|
||||
os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]):
|
||||
if _is_64bit:
|
||||
@@ -251,11 +251,11 @@ def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_pre
|
||||
pass
|
||||
# Debian-specific dist-packages directories:
|
||||
sitedirs.append(os.path.join(prefix, "local/lib",
|
||||
- "python" + sys.version[:3],
|
||||
+ "python%s.%s" % (sys.version_info[0], sys.version_info[1]),
|
||||
"dist-packages"))
|
||||
if sys.version[0] == '2':
|
||||
sitedirs.append(os.path.join(prefix, "lib",
|
||||
- "python" + sys.version[:3],
|
||||
+ "python%s.%s" % (sys.version_info[0], sys.version_info[1]),
|
||||
"dist-packages"))
|
||||
else:
|
||||
sitedirs.append(os.path.join(prefix, "lib",
|
||||
@@ -275,7 +275,7 @@ def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_pre
|
||||
os.path.join(home,
|
||||
'Library',
|
||||
'Python',
|
||||
- sys.version[:3],
|
||||
+ '%s.%s' % (sys.version_info[0], sys.version_info[1]),
|
||||
'site-packages'))
|
||||
for sitedir in sitedirs:
|
||||
if os.path.isdir(sitedir):
|
||||
@@ -335,7 +335,7 @@ def addusersitepackages(known_paths):
|
||||
else:
|
||||
USER_BASE = joinuser(base, "Python")
|
||||
USER_SITE = os.path.join(USER_BASE,
|
||||
- "Python" + sys.version[0] + sys.version[2],
|
||||
+ "Python%s%s" % (sys.version_info[0], sys.version_info[1]),
|
||||
"site-packages")
|
||||
else:
|
||||
if env_base:
|
||||
@@ -343,7 +343,7 @@ def addusersitepackages(known_paths):
|
||||
else:
|
||||
USER_BASE = joinuser("~", ".local")
|
||||
USER_SITE = os.path.join(USER_BASE, "lib",
|
||||
- "python" + sys.version[:3],
|
||||
+ "python%s.%s" % (sys.version_info[0], sys.version_info[1]),
|
||||
"site-packages")
|
||||
|
||||
if ENABLE_USER_SITE and os.path.isdir(USER_SITE):
|
||||
@@ -351,7 +351,7 @@ def addusersitepackages(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],
|
||||
+ "python%s.%s" % (sys.version_info[0], sys.version_info[1]),
|
||||
"dist-packages")
|
||||
if os.path.isdir(user_site):
|
||||
addsitedir(user_site, known_paths)
|
||||
@@ -426,7 +426,7 @@ class _Printer(object):
|
||||
for filename in self.__files:
|
||||
filename = os.path.join(dir, filename)
|
||||
try:
|
||||
- fp = open(filename, "rU")
|
||||
+ fp = open(filename, "r")
|
||||
data = fp.read()
|
||||
fp.close()
|
||||
break
|
||||
@@ -581,9 +581,9 @@ def virtual_install_main_packages():
|
||||
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])]
|
||||
+ paths = [os.path.join(sys.real_prefix, 'lib', 'python%s.%s' % (sys.version_info[0], sys.version_info[1]))]
|
||||
hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
|
||||
- lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python'+sys.version[:3])
|
||||
+ lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python%s.%s' % (sys.version_info[0], sys.version_info[1]))
|
||||
if os.path.exists(lib64_path):
|
||||
if _is_64bit:
|
||||
paths.insert(0, lib64_path)
|
||||
@@ -600,7 +600,7 @@ def virtual_install_main_packages():
|
||||
# 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],
|
||||
+ 'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
|
||||
'plat-%s' % arch)
|
||||
if os.path.exists(plat_path):
|
||||
paths.append(plat_path)
|
@ -0,0 +1,20 @@
|
||||
diff --git a/virtualenv.py b/virtualenv.py
|
||||
index e5d0883..34d2160 100755
|
||||
--- a/virtualenv.py
|
||||
+++ b/virtualenv.py
|
||||
@@ -4,6 +4,15 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
+# The way virtualenv < 20 creates virtual environments
|
||||
+# is not compatible with Python 3.11+ "frozen standard library modules"
|
||||
+# https://docs.python.org/3.11/whatsnew/3.11.html#frozen-imports-static-code-objects
|
||||
+if sys.version_info >= (3, 11):
|
||||
+ venv_cmd = 'python{0.major}.{0.minor} -m venv'.format(sys.version_info)
|
||||
+ sys.exit('ERROR: Virtual environments created by virtualenv < 20 '
|
||||
+ 'are not compatible with Python 3.11.\n'
|
||||
+ 'ERROR: Use `{}` instead.'.format(venv_cmd))
|
||||
+
|
||||
# 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
|
@ -0,0 +1,125 @@
|
||||
From b7b8a713d9f1ebac6430fd0fc10175ed37b834ee Mon Sep 17 00:00:00 2001
|
||||
From: Lumir Balhar <lbalhar@redhat.com>
|
||||
Date: Thu, 18 Mar 2021 13:08:52 +0100
|
||||
Subject: [PATCH] rpm
|
||||
|
||||
---
|
||||
virtualenv.py | 66 ++++++++++++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 55 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/virtualenv.py b/virtualenv.py
|
||||
index 5699998..9854324 100755
|
||||
--- a/virtualenv.py
|
||||
+++ b/virtualenv.py
|
||||
@@ -39,9 +39,9 @@ except ImportError:
|
||||
__version__ = "15.1.0"
|
||||
virtualenv_version = __version__ # legacy
|
||||
|
||||
-if sys.version_info < (2, 6):
|
||||
+if sys.version_info < (2, 7):
|
||||
print('ERROR: %s' % sys.exc_info()[1])
|
||||
- print('ERROR: this script requires Python 2.6 or greater.')
|
||||
+ print('ERROR: this script requires Python 2.7 or greater.')
|
||||
sys.exit(101)
|
||||
|
||||
try:
|
||||
@@ -399,6 +399,8 @@ def _find_file(filename, dirs):
|
||||
def file_search_dirs():
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
dirs = [here, join(here, 'virtualenv_support')]
|
||||
+ dirs.insert(1, '/usr/share/python{}-wheels'.format(sys.version_info[0]))
|
||||
+ dirs.insert(1, '/usr/share/python{}{}-wheels'.format(*sys.version_info[:2]))
|
||||
if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
|
||||
# Probably some boot script; just in case virtualenv is installed...
|
||||
try:
|
||||
@@ -859,7 +861,12 @@ def install_wheel(project_names, py_executable, search_dirs=None,
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
- import pip
|
||||
+ try:
|
||||
+ from pip._internal import main as _main
|
||||
+ if type(_main) is type(sys): # <type 'module'>
|
||||
+ _main = _main.main # nested starting in Pip 19.3
|
||||
+ except ImportError:
|
||||
+ from pip import main as _main
|
||||
|
||||
try:
|
||||
cert_data = pkgutil.get_data("pip._vendor.requests", "cacert.pem")
|
||||
@@ -878,7 +885,7 @@ def install_wheel(project_names, py_executable, search_dirs=None,
|
||||
args += ["--cert", cert_file.name]
|
||||
args += sys.argv[1:]
|
||||
|
||||
- sys.exit(pip.main(args))
|
||||
+ sys.exit(_main(args))
|
||||
finally:
|
||||
if cert_file is not None:
|
||||
os.remove(cert_file.name)
|
||||
@@ -1038,20 +1045,57 @@ def change_prefix(filename, dst_prefix):
|
||||
assert False, "Filename %s does not start with any of these prefixes: %s" % \
|
||||
(filename, prefixes)
|
||||
|
||||
-def copy_required_modules(dst_prefix, symlink):
|
||||
- import imp
|
||||
+def find_module_filename(modname):
|
||||
+ if sys.version_info < (3, 4):
|
||||
+ # noinspection PyDeprecation
|
||||
+ import imp
|
||||
+
|
||||
+ try:
|
||||
+ file_handler, filepath, _ = imp.find_module(modname)
|
||||
+ except ImportError:
|
||||
+ return None
|
||||
+ else:
|
||||
+ if file_handler is not None:
|
||||
+ file_handler.close()
|
||||
+ return filepath
|
||||
+ else:
|
||||
+ import importlib.util
|
||||
|
||||
+ if sys.version_info < (3, 5):
|
||||
+
|
||||
+ def find_spec(modname):
|
||||
+ # noinspection PyDeprecation
|
||||
+ loader = importlib.find_loader(modname)
|
||||
+ if loader is None:
|
||||
+ return None
|
||||
+ else:
|
||||
+ return importlib.util.spec_from_loader(modname, loader)
|
||||
+
|
||||
+ else:
|
||||
+ find_spec = importlib.util.find_spec
|
||||
+
|
||||
+ spec = find_spec(modname)
|
||||
+ if spec is None:
|
||||
+ return None
|
||||
+ if not os.path.exists(spec.origin):
|
||||
+ # https://bitbucket.org/pypy/pypy/issues/2944/origin-for-several-builtin-modules
|
||||
+ # on pypy3, some builtin modules have a bogus build-time file path, ignore them
|
||||
+ return None
|
||||
+ filepath = spec.origin
|
||||
+ # https://www.python.org/dev/peps/pep-3147/#file guarantee to be non-cached
|
||||
+ if os.path.basename(filepath) == "__init__.py":
|
||||
+ filepath = os.path.dirname(filepath)
|
||||
+ return filepath
|
||||
+
|
||||
+def copy_required_modules(dst_prefix, symlink):
|
||||
for modname in REQUIRED_MODULES:
|
||||
if modname in sys.builtin_module_names:
|
||||
logger.info("Ignoring built-in bootstrap module: %s" % modname)
|
||||
continue
|
||||
- try:
|
||||
- f, filename, _ = imp.find_module(modname)
|
||||
- except ImportError:
|
||||
+ filename = find_module_filename(modname)
|
||||
+ if filename is None:
|
||||
logger.info("Cannot import bootstrap module: %s" % modname)
|
||||
else:
|
||||
- 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'))):
|
||||
--
|
||||
2.30.2
|
||||
|
@ -1,390 +0,0 @@
|
||||
* Wed Jan 03 2024 Miro Hrončok <mhroncok@redhat.com> - 20.21.1-1
|
||||
- Update to 20.21.1
|
||||
- Backport from 20.23.0: Don't install setuptools and wheel to Python 3.12+ environments
|
||||
- Add RPM Requires needed for Python 3.12
|
||||
|
||||
* Thu Jul 27 2023 Benjamin A. Beasley <code@musicinmybrain.net> - 20.20.0-2
|
||||
- Remove workarounds for old hatchling
|
||||
|
||||
* Wed Mar 01 2023 Lumír Balhar <lbalhar@redhat.com> - 20.20.0-1
|
||||
- Update to 20.20.0 (rhbz#2174221)
|
||||
|
||||
* Thu Feb 09 2023 Lumír Balhar <lbalhar@redhat.com> - 20.19.0-1
|
||||
- Update to 20.19.0 (rhbz#2167499)
|
||||
|
||||
* Mon Jan 30 2023 Miro Hrončok <mhroncok@redhat.com> - 20.17.1-2
|
||||
- Use wheels from /usr/share/python3.11-wheels when creating Python 3.11 virtual environments
|
||||
- Require Python 3.11 wheels when Python 3.11 is installed
|
||||
|
||||
* Wed Dec 07 2022 Lumír Balhar <lbalhar@redhat.com> - 20.17.1-1
|
||||
- Update to 20.17.1 (rhbz#2151044)
|
||||
|
||||
* Thu Dec 01 2022 Lumír Balhar <lbalhar@redhat.com> - 20.17.0-1
|
||||
- Update to 20.17.0 (rhbz#2148907)
|
||||
|
||||
* Mon Nov 14 2022 Lumír Balhar <lbalhar@redhat.com> - 20.16.7-1
|
||||
- Update to 20.16.7 (#2142311)
|
||||
|
||||
* Thu Oct 27 2022 Lumír Balhar <lbalhar@redhat.com> - 20.16.6-1
|
||||
- Update to 20.16.6
|
||||
Resolves: rhbz#2137713
|
||||
|
||||
* Wed Jun 29 2022 Lumír Balhar <lbalhar@redhat.com> - 20.15.1-1
|
||||
- Update to 20.15.1
|
||||
Resolves: rhbz#2101975
|
||||
|
||||
* Sun Jun 26 2022 Lumír Balhar <lbalhar@redhat.com> - 20.15.0-1
|
||||
- Update to 20.15.0
|
||||
Resolves: rhbz#2101126
|
||||
|
||||
* Mon Mar 21 2022 Lumír Balhar <lbalhar@redhat.com> - 20.13.4-1
|
||||
- Update to 20.13.4
|
||||
Resolves: rhbz#2065839
|
||||
|
||||
* Mon Mar 14 2022 Benjamin A. Beasley <code@musicinmybrain.net> - 20.13.3-3
|
||||
- BR tcsh so we can test csh activation scripts
|
||||
|
||||
* Mon Mar 14 2022 Lumír Balhar <lbalhar@redhat.com> - 20.13.3-2
|
||||
- Add explicit error when embed version of wheels is requested
|
||||
Resolves: rhbz#2053948
|
||||
|
||||
* Tue Mar 08 2022 Lumír Balhar <lbalhar@redhat.com> - 20.13.3-1
|
||||
- Update to 20.13.3
|
||||
Resolves: rhbz#2061449
|
||||
|
||||
* Fri Feb 25 2022 Lumír Balhar <lbalhar@redhat.com> - 20.13.2-1
|
||||
- Update to 20.13.2
|
||||
Resolves: rhbz#2058146
|
||||
|
||||
* Sun Feb 06 2022 Lumír Balhar <lbalhar@redhat.com> - 20.13.1-1
|
||||
- Update to 20.13.1
|
||||
Resolves: rhbz#2051025
|
||||
|
||||
* Mon Jan 03 2022 Lumír Balhar <lbalhar@redhat.com> - 20.13.0-1
|
||||
- Update to 20.13.0
|
||||
Resolves: rhbz#2035895
|
||||
|
||||
* Mon Nov 08 2021 Lumír Balhar <lbalhar@redhat.com> - 20.10.0-2
|
||||
- Remove hack for local/ prefixes
|
||||
|
||||
* Tue Nov 02 2021 Lumír Balhar <lbalhar@redhat.com> - 20.10.0-1
|
||||
- Update to 20.10.0
|
||||
Resolves: rhbz#2019116
|
||||
|
||||
* Mon Oct 25 2021 Lumír Balhar <lbalhar@redhat.com> - 20.9.0-1
|
||||
- Update to 20.9.0
|
||||
Resolves: rhbz#2016758
|
||||
|
||||
* Wed Oct 06 2021 Lumír Balhar <lbalhar@redhat.com> - 20.8.1-1
|
||||
- Update to 20.8.1
|
||||
Resoves: rhbz#2007595
|
||||
|
||||
* Wed Oct 06 2021 Miro Hrončok <mhroncok@redhat.com> - 20.7.2-2
|
||||
- Remove /local/ part from virtualenv paths
|
||||
Resolves: rhbz#2011455
|
||||
|
||||
* Mon Aug 16 2021 Lumír Balhar <lbalhar@redhat.com> - 20.7.2-1
|
||||
- Update to 20.7.2
|
||||
Resolves: rhbz#1991618
|
||||
|
||||
* Sun Aug 01 2021 Lumír Balhar <lbalhar@redhat.com> - 20.7.0-1
|
||||
- Update to 20.7.0
|
||||
Resolves: rhbz#1988721
|
||||
|
||||
* Wed Jul 21 2021 Lumír Balhar <lbalhar@redhat.com> - 20.6.0-1
|
||||
- Update to 20.6.0
|
||||
Resolves: rhbz#1981792
|
||||
|
||||
* Fri Jun 04 2021 Python Maint <python-maint@redhat.com> - 20.4.7-3
|
||||
- Rebuilt for Python 3.10
|
||||
|
||||
* Wed Jun 02 2021 Python Maint <python-maint@redhat.com> - 20.4.7-2
|
||||
- Bootstrap for Python 3.10
|
||||
|
||||
* Tue May 25 2021 Lumír Balhar <lbalhar@redhat.com> - 20.4.7-1
|
||||
- Update to 20.4.7
|
||||
Resolves: rhbz#1964115
|
||||
|
||||
* Wed Apr 21 2021 Lumír Balhar <lbalhar@redhat.com> - 20.4.4-1
|
||||
- Update to 20.4.4
|
||||
Resolves: rhbz#1951515
|
||||
|
||||
* Wed Mar 17 2021 Lumír Balhar <lbalhar@redhat.com> - 20.4.3-1
|
||||
- Update to 20.4.3
|
||||
Resolves: rhbz#1939428
|
||||
|
||||
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 20.4.0-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||
|
||||
* Tue Jan 19 2021 Lumír Balhar <lbalhar@redhat.com> - 20.4.0-1
|
||||
- Update to 20.4.0 (#1915682)
|
||||
|
||||
* Tue Jan 12 2021 Lumír Balhar <lbalhar@redhat.com> - 20.3.0-1
|
||||
- Update to 20.3.0 (#1914641)
|
||||
|
||||
* Mon Nov 23 2020 Lumír Balhar <lbalhar@redhat.com> - 20.2.1-1
|
||||
- Update to 20.2.1 (#1900253)
|
||||
|
||||
* Wed Nov 18 2020 Lumír Balhar <lbalhar@redhat.com> - 20.1.0-1
|
||||
- Update to 20.1.0 (#1891297)
|
||||
|
||||
* Fri Oct 02 2020 Lumír Balhar <lbalhar@redhat.com> - 20.0.32-1
|
||||
- Update to 20.0.32 (#1884449)
|
||||
|
||||
* Thu Sep 03 2020 Lumír Balhar <lbalhar@redhat.com> - 20.0.31-1
|
||||
- Update to 20.0.31 (#1869352)
|
||||
|
||||
* Thu Aug 06 2020 Lumír Balhar <lbalhar@redhat.com> - 20.0.30-1
|
||||
- Update to 20.0.30 (#1862562)
|
||||
|
||||
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 20.0.28-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||
|
||||
* Fri Jul 24 2020 Miro Hrončok <mhroncok@redhat.com> - 20.0.28-1
|
||||
- Update to 20.0.28
|
||||
- Fixes rhbz#1860272
|
||||
|
||||
* Thu Jul 23 2020 Lumír Balhar <lbalhar@redhat.com> - 20.0.27-1
|
||||
- Update to 20.0.27 (#1854551)
|
||||
|
||||
* Tue Jun 23 2020 Lumír Balhar <lbalhar@redhat.com> - 20.0.25-1
|
||||
- Update to 20.0.25
|
||||
|
||||
* Mon Jun 15 2020 Lumír Balhar <lbalhar@redhat.com> - 20.0.23-1
|
||||
- Update to 20.0.23 (#1742034)
|
||||
|
||||
* Sat May 23 2020 Miro Hrončok <mhroncok@redhat.com> - 16.7.10-2
|
||||
- Rebuilt for Python 3.9
|
||||
|
||||
* Tue Feb 25 2020 Miro Hrončok <mhroncok@redhat.com> - 16.7.10-1
|
||||
- Update to 16.7.10
|
||||
- Explicitly require setuptools < 44 with Python 3.4
|
||||
|
||||
* Thu Jan 30 2020 Fedora Release Engineering <releng@fedoraproject.org> - 16.7.3-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||
|
||||
* Tue Sep 03 2019 Miro Hrončok <mhroncok@redhat.com> - 16.7.3-2
|
||||
- Prefer wheels bundled in Python's ensurepip module over the RPM built ones
|
||||
- This allows continuing support for Python 3.4 in Fedora 32+
|
||||
|
||||
* Wed Aug 21 2019 Charalampos Stratakis <cstratak@redhat.com> - 16.7.3-1
|
||||
- Update to 16.7.3 (#1742034)
|
||||
|
||||
* Fri Aug 16 2019 Miro Hrončok <mhroncok@redhat.com> - 16.6.1-3
|
||||
- Rebuilt for Python 3.8
|
||||
|
||||
* Mon Jul 29 2019 Miro Hrončok <mhroncok@redhat.com> - 16.6.1-2
|
||||
- Drop python2-virtualenv
|
||||
|
||||
* Thu Jul 11 2019 Miro Hrončok <mhroncok@redhat.com> - 16.6.1-1
|
||||
- Update to 16.6.1 (#1699031)
|
||||
- No more Python 2.6 or Jython support
|
||||
- Drop runtime dependency on pythonX-devel
|
||||
|
||||
* Sat Feb 02 2019 Fedora Release Engineering <releng@fedoraproject.org> - 16.0.0-7
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
||||
|
||||
* Thu Dec 13 2018 Miro Hrončok <mhroncok@redhat.com> - 16.0.0-6
|
||||
- Don't fail on missing certifi's cert bundle (#1655253)
|
||||
|
||||
* Wed Aug 15 2018 Miro Hrončok <mhroncok@redhat.com> - 16.0.0-5
|
||||
- Use wheels from RPM packages
|
||||
- Put wheels needed for Python 2.6 into a subpackage
|
||||
- Only have one /usr/bin/virtualenv (#1599422)
|
||||
- Provide "virtualenv" (#1502670)
|
||||
|
||||
* Wed Jul 18 2018 Miro Hrončok <mhroncok@redhat.com> - 16.0.0-4
|
||||
- Reintroduce support for Python 2.6 (#1602347)
|
||||
- Add missing bundled provides
|
||||
|
||||
* Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 16.0.0-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
||||
|
||||
* Sat Jun 16 2018 Miro Hrončok <mhroncok@redhat.com> - 16.0.0-2
|
||||
- Rebuilt for Python 3.7
|
||||
|
||||
* Thu May 17 2018 Steve Milner <smilner@redhat.com> - 16.0.0-1
|
||||
- Updated for upstream release.
|
||||
|
||||
* Wed Feb 28 2018 Iryna Shcherbina <ishcherb@redhat.com> - 15.1.0-5
|
||||
- Update Python 2 dependency declarations to new packaging standards
|
||||
(See https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3)
|
||||
|
||||
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 15.1.0-4
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
||||
|
||||
* Fri Sep 29 2017 Troy Dawson <tdawson@redhat.com> - 15.1.0-3
|
||||
- Cleanup spec file conditionals
|
||||
|
||||
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 15.1.0-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
|
||||
|
||||
* Mon Jun 12 2017 Steve Milner <smilner@redhat.com> - 15.1.0-1
|
||||
- Update to 15.1.0 per https://bugzilla.redhat.com/show_bug.cgi?id=1454962
|
||||
|
||||
* Fri Feb 17 2017 Michal Cyprian <mcyprian@redhat.com> - 15.0.3-6
|
||||
- Check if exec_dir exists before listing it's content during venv create process
|
||||
|
||||
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 15.0.3-5
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
|
||||
|
||||
* Wed Jan 4 2017 Steve Milner <smilner@redhat.com> - 15.0.3-4
|
||||
- Updated version binaries per discussion at bz#1385240.
|
||||
|
||||
* Tue Dec 13 2016 Stratakis Charalampos <cstratak@redhat.com> - 15.0.3-3
|
||||
- Rebuild for Python 3.6
|
||||
|
||||
* Mon Oct 17 2016 Steve Milner <smilner@redhat.com> - 15.0.3-2
|
||||
- Added MAJOR symlinks per bz#1385240.
|
||||
|
||||
* Mon Aug 8 2016 Steve Milner <smilner@redhat.com> - 15.0.3-1
|
||||
- Update for upstream release.
|
||||
|
||||
* Tue Jul 19 2016 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 14.0.6-2
|
||||
- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
|
||||
|
||||
* Sun Feb 21 2016 Orion Poplawski <orion@cora.nwra.com> - 14.0.6-1
|
||||
- Update to 14.0.6
|
||||
|
||||
* Tue Feb 2 2016 Orion Poplawski <orion@cora.nwra.com> - 13.1.2-4
|
||||
- Modernize spec
|
||||
- Fix python3 package file ownership
|
||||
|
||||
* Wed Dec 2 2015 Orion Poplawski <orion@cora.nwra.com> - 13.1.2-3
|
||||
- Move documentation to separate package (bug #1219139)
|
||||
|
||||
* Wed Oct 14 2015 Robert Kuska <rkuska@redhat.com> - 13.1.2-2
|
||||
- Rebuilt for Python3.5 rebuild
|
||||
|
||||
* Mon Aug 24 2015 Steve Milner <smilner@redhat.com> - 13.1.2-1
|
||||
- Update for upstream release.
|
||||
|
||||
* Thu Jun 18 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 12.0.7-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
|
||||
|
||||
* Mon Mar 16 2015 Matej Stuchlik <mstuchli@redhat.com> - 12.0.7-1
|
||||
- Update to 12.0.7
|
||||
|
||||
* Thu Jan 15 2015 Matthias Runge <mrunge@redhat.com> - 1.11.6-2
|
||||
- add a python3-package, thanks to Matej Stuchlik (rhbz#1179150)
|
||||
|
||||
* Wed Jul 09 2014 Matthias Runge <mrunge@redhat.com> - 1.11.6-1
|
||||
- update to 1.11.6:
|
||||
Upstream updated setuptools to 3.6, updated pip to 1.5.6
|
||||
|
||||
* Sun Jun 08 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.10.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
|
||||
|
||||
* Thu Aug 15 2013 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.10.1-1
|
||||
- Upstream upgraded pip to v1.4.1
|
||||
- Upstream upgraded setuptools to v0.9.8 (fixes CVE-2013-1633)
|
||||
|
||||
* Sun Aug 04 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.9.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
|
||||
|
||||
* Tue May 14 2013 Toshio Kuratomi <toshio@fedoraproject.org> - 1.9.1-1
|
||||
- Update to upstream 1.9.1 because of security issues with the bundled
|
||||
python-pip in older releases. This is just a quick fix until a
|
||||
python-virtualenv maintainer can unbundle the python-pip package
|
||||
see: https://bugzilla.redhat.com/show_bug.cgi?id=749378
|
||||
|
||||
* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.2-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
|
||||
|
||||
* Tue Aug 14 2012 Steve Milner <me@stevemilner.org> - 1.7.2-1
|
||||
- Update for upstream bug fixes.
|
||||
- Added path for versioned binary.
|
||||
- Patch no longer required.
|
||||
|
||||
* Sat Jul 21 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.1.2-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
|
||||
|
||||
* Wed Mar 14 2012 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.7.1.2-1
|
||||
- Update for upstream bug fixes.
|
||||
- Added patch for sphinx building
|
||||
|
||||
* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
|
||||
|
||||
* Tue Dec 20 2011 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.7-1
|
||||
- Update for https://bugzilla.redhat.com/show_bug.cgi?id=769067
|
||||
|
||||
* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.5.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
|
||||
|
||||
* Sat Oct 16 2010 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.5.1-1
|
||||
- Added _weakrefset requirement for Python 2.7.1.
|
||||
- Add support for PyPy.
|
||||
- Uses a proper temporary dir when installing environment requirements.
|
||||
- Add --prompt option to be able to override the default prompt prefix.
|
||||
- Add fish and csh activate scripts.
|
||||
|
||||
* Thu Jul 22 2010 David Malcolm <dmalcolm@redhat.com> - 1.4.8-4
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild
|
||||
|
||||
* Wed Jul 7 2010 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.4.8-3
|
||||
- Fixed EPEL installation issue from BZ#611536
|
||||
|
||||
* Wed Jun 9 2010 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.4.8-2
|
||||
- Only replace the python shebang on the first line (Robert Buchholz)
|
||||
|
||||
* Wed Apr 28 2010 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.4.8-1
|
||||
- update pip to 0.7
|
||||
- move regen-docs into bin/
|
||||
- Fix #31, make activate_this.py work on Windows (use Lib/site-packages)
|
||||
unset PYTHONHOME envioronment variable -- first step towards fixing the PYTHONHOME issue; see e.g. https://bugs.launchpad.net/virtualenv/+bug/290844
|
||||
- unset PYTHONHOME in the (Unix) activate script (and reset it in deactivate())
|
||||
- use the activate.sh in virtualenv.py via running bin/rebuild-script.py
|
||||
- add warning message if PYTHONHOME is set
|
||||
|
||||
* Fri Apr 2 2010 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.4.6-1
|
||||
- allow script creation without setuptools
|
||||
- fix problem with --relocate when bin/ has subdirs (fixes #12)
|
||||
- Allow more flexible .pth file fixup
|
||||
- make nt a required module, along with posix. it may not be a builtin module on jython
|
||||
- don't mess with PEP 302-supplied __file__, from CPython, and merge in a small startup optimization for Jython, from Jython
|
||||
|
||||
* Tue Dec 22 2009 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.4.3-1
|
||||
- Updated for upstream release.
|
||||
|
||||
* Thu Nov 12 2009 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.4.2-1
|
||||
- Updated for upstream release.
|
||||
|
||||
* Sun Jul 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.3.3-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
|
||||
|
||||
* Tue Apr 28 2009 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.3.3-1
|
||||
- Updated for upstream release.
|
||||
|
||||
* Thu Feb 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.3.2-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
|
||||
|
||||
* Thu Dec 25 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.3.2-1
|
||||
- Updated for upstream release.
|
||||
|
||||
* Thu Dec 04 2008 Ignacio Vazquez-Abrams <ivazqueznet+rpm@gmail.com> - 1.3.1-4
|
||||
- Rebuild for Python 2.6
|
||||
|
||||
* Mon Dec 1 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.3.1-3
|
||||
- Added missing dependencies.
|
||||
|
||||
* Sat Nov 29 2008 Ignacio Vazquez-Abrams <ivazqueznet+rpm@gmail.com> - 1.3.1-2
|
||||
- Rebuild for Python 2.6
|
||||
|
||||
* Fri Nov 28 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.3.1-1
|
||||
- Updated for upstream release
|
||||
|
||||
* Sun Sep 28 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.3-1
|
||||
- Updated for upstream release
|
||||
|
||||
* Sat Aug 30 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.2-1
|
||||
- Updated for upstream release
|
||||
|
||||
* Fri Aug 29 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.1-3
|
||||
- Updated from review notes
|
||||
|
||||
* Thu Aug 28 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.1-2
|
||||
- Updated from review notes
|
||||
|
||||
* Tue Aug 26 2008 Steve 'Ashcrow' Milner <me@stevemilner.org> - 1.1-1
|
||||
- Initial Version
|
@ -1,70 +0,0 @@
|
||||
From fc8e412fa8fe524ab3f112f02e865aa42608388b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jakub=20Kul=C3=ADk?= <Kulikjak@gmail.com>
|
||||
Date: Thu, 27 Apr 2023 18:52:38 +0200
|
||||
Subject: [PATCH] prevent PermissionError when using venv creator on some
|
||||
systems (#2543)
|
||||
|
||||
Cherry-picked from 0597a2f8ab32705b86a25dbd1d42fd30c3033061
|
||||
---
|
||||
docs/changelog/2543.bugfix.rst | 2 ++
|
||||
src/virtualenv/activation/via_template.py | 4 ++++
|
||||
tests/unit/create/test_creator.py | 22 ++++++++++++++++++++++
|
||||
3 files changed, 28 insertions(+)
|
||||
create mode 100644 docs/changelog/2543.bugfix.rst
|
||||
|
||||
diff --git a/docs/changelog/2543.bugfix.rst b/docs/changelog/2543.bugfix.rst
|
||||
new file mode 100644
|
||||
index 0000000..5f0d6ca
|
||||
--- /dev/null
|
||||
+++ b/docs/changelog/2543.bugfix.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
+Prevent ``PermissionError`` when using venv creator on systems that deliver files without user write
|
||||
+permission - by :user:`kulikjak`.
|
||||
diff --git a/src/virtualenv/activation/via_template.py b/src/virtualenv/activation/via_template.py
|
||||
index 069d52e..cc9dbda 100644
|
||||
--- a/src/virtualenv/activation/via_template.py
|
||||
+++ b/src/virtualenv/activation/via_template.py
|
||||
@@ -41,6 +41,10 @@ class ViaTemplateActivator(Activator, metaclass=ABCMeta):
|
||||
for template in templates:
|
||||
text = self.instantiate_template(replacements, template, creator)
|
||||
dest = to_folder / self.as_name(template)
|
||||
+ # remove the file if it already exists - this prevents permission
|
||||
+ # errors when the dest is not writable
|
||||
+ if dest.exists():
|
||||
+ dest.unlink()
|
||||
# use write_bytes to avoid platform specific line normalization (\n -> \r\n)
|
||||
dest.write_bytes(text.encode("utf-8"))
|
||||
generated.append(dest)
|
||||
diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py
|
||||
index ea61ed0..0ec6d62 100644
|
||||
--- a/tests/unit/create/test_creator.py
|
||||
+++ b/tests/unit/create/test_creator.py
|
||||
@@ -690,3 +690,25 @@ def test_py_pyc_missing(tmp_path, mocker, py, pyc):
|
||||
|
||||
pyc_at = Python2.from_stdlib(Python2.mappings(CURRENT), "osc.py")[1](result.creator, Path("os.pyc"))
|
||||
assert pyc_at.exists() is pyc
|
||||
+
|
||||
+
|
||||
+# Make sure that the venv creator works on systems where vendor-delivered files
|
||||
+# (specifically venv scripts delivered with Python itself) are not writable.
|
||||
+#
|
||||
+# https://github.com/pypa/virtualenv/issues/2419
|
||||
+@pytest.mark.skipif("venv" not in CURRENT_CREATORS, reason="test needs venv creator")
|
||||
+def test_venv_creator_without_write_perms(tmp_path, mocker):
|
||||
+ from virtualenv.run.session import Session
|
||||
+
|
||||
+ prev = Session._create
|
||||
+
|
||||
+ def func(self):
|
||||
+ prev(self)
|
||||
+ scripts_dir = self.creator.dest / "bin"
|
||||
+ for script in scripts_dir.glob("*ctivate*"):
|
||||
+ script.chmod(stat.S_IREAD | stat.S_IRGRP | stat.S_IROTH)
|
||||
+
|
||||
+ mocker.patch("virtualenv.run.session.Session._create", side_effect=func, autospec=True)
|
||||
+
|
||||
+ cmd = [str(tmp_path), "--seeder", "app-data", "--without-pip", "--creator", "venv"]
|
||||
+ cli_run(cmd)
|
||||
--
|
||||
2.40.0
|
||||
|
@ -1,445 +0,0 @@
|
||||
From 82dbaffa36fe317e331b2d22c5efbb6a0b6c7b19 Mon Sep 17 00:00:00 2001
|
||||
From: Lumir Balhar <lbalhar@redhat.com>
|
||||
Date: Tue, 8 Oct 2024 09:15:09 +0200
|
||||
Subject: [PATCH] Prevent command injection
|
||||
|
||||
---
|
||||
docs/changelog/2768.bugfix.rst | 2 ++
|
||||
src/virtualenv/activation/bash/activate.sh | 9 +++++----
|
||||
src/virtualenv/activation/batch/__init__.py | 4 ++++
|
||||
src/virtualenv/activation/cshell/activate.csh | 10 +++++-----
|
||||
src/virtualenv/activation/fish/activate.fish | 8 ++++----
|
||||
src/virtualenv/activation/nushell/__init__.py | 19 ++++++++++++++++++
|
||||
src/virtualenv/activation/nushell/activate.nu | 8 ++++----
|
||||
.../activation/powershell/__init__.py | 12 +++++++++++
|
||||
.../activation/powershell/activate.ps1 | 6 +++---
|
||||
src/virtualenv/activation/python/__init__.py | 6 +++++-
|
||||
.../activation/python/activate_this.py | 6 +++---
|
||||
src/virtualenv/activation/via_template.py | 15 ++++++++++++--
|
||||
tests/conftest.py | 6 +++++-
|
||||
tests/unit/activation/conftest.py | 3 +--
|
||||
tests/unit/activation/test_batch.py | 10 +++++-----
|
||||
tests/unit/activation/test_powershell.py | 20 ++++++++++++++-----
|
||||
16 files changed, 105 insertions(+), 39 deletions(-)
|
||||
create mode 100644 docs/changelog/2768.bugfix.rst
|
||||
|
||||
diff --git a/docs/changelog/2768.bugfix.rst b/docs/changelog/2768.bugfix.rst
|
||||
new file mode 100644
|
||||
index 0000000..7651eb6
|
||||
--- /dev/null
|
||||
+++ b/docs/changelog/2768.bugfix.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
+Properly quote string placeholders in activation script templates to mitigate
|
||||
+potential command injection - by :user:`y5c4l3`.
|
||||
diff --git a/src/virtualenv/activation/bash/activate.sh b/src/virtualenv/activation/bash/activate.sh
|
||||
index fb40db6..d047ea4 100644
|
||||
--- a/src/virtualenv/activation/bash/activate.sh
|
||||
+++ b/src/virtualenv/activation/bash/activate.sh
|
||||
@@ -44,14 +44,14 @@ deactivate () {
|
||||
# unset irrelevant variables
|
||||
deactivate nondestructive
|
||||
|
||||
-VIRTUAL_ENV='__VIRTUAL_ENV__'
|
||||
+VIRTUAL_ENV=__VIRTUAL_ENV__
|
||||
if ([ "$OSTYPE" = "cygwin" ] || [ "$OSTYPE" = "msys" ]) && $(command -v cygpath &> /dev/null) ; then
|
||||
VIRTUAL_ENV=$(cygpath -u "$VIRTUAL_ENV")
|
||||
fi
|
||||
export VIRTUAL_ENV
|
||||
|
||||
_OLD_VIRTUAL_PATH="$PATH"
|
||||
-PATH="$VIRTUAL_ENV/__BIN_NAME__:$PATH"
|
||||
+PATH="$VIRTUAL_ENV/"__BIN_NAME__":$PATH"
|
||||
export PATH
|
||||
|
||||
# unset PYTHONHOME if set
|
||||
@@ -62,8 +62,9 @@ fi
|
||||
|
||||
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then
|
||||
_OLD_VIRTUAL_PS1="${PS1-}"
|
||||
- if [ "x__VIRTUAL_PROMPT__" != x ] ; then
|
||||
- PS1="(__VIRTUAL_PROMPT__) ${PS1-}"
|
||||
+ if [ "x"__VIRTUAL_PROMPT__ != x ] ; then
|
||||
+ PROMPT=__VIRTUAL_PROMPT__
|
||||
+ PS1="(${PROMPT}) ${PS1-}"
|
||||
else
|
||||
PS1="(`basename \"$VIRTUAL_ENV\"`) ${PS1-}"
|
||||
fi
|
||||
diff --git a/src/virtualenv/activation/batch/__init__.py b/src/virtualenv/activation/batch/__init__.py
|
||||
index 13ba097..b3e8540 100644
|
||||
--- a/src/virtualenv/activation/batch/__init__.py
|
||||
+++ b/src/virtualenv/activation/batch/__init__.py
|
||||
@@ -13,6 +13,10 @@ class BatchActivator(ViaTemplateActivator):
|
||||
yield "deactivate.bat"
|
||||
yield "pydoc.bat"
|
||||
|
||||
+ @staticmethod
|
||||
+ def quote(string):
|
||||
+ return string
|
||||
+
|
||||
def instantiate_template(self, replacements, template, creator):
|
||||
# ensure the text has all newlines as \r\n - required by batch
|
||||
base = super().instantiate_template(replacements, template, creator)
|
||||
diff --git a/src/virtualenv/activation/cshell/activate.csh b/src/virtualenv/activation/cshell/activate.csh
|
||||
index 837dcda..fcec426 100644
|
||||
--- a/src/virtualenv/activation/cshell/activate.csh
|
||||
+++ b/src/virtualenv/activation/cshell/activate.csh
|
||||
@@ -10,15 +10,15 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
-setenv VIRTUAL_ENV '__VIRTUAL_ENV__'
|
||||
+setenv VIRTUAL_ENV __VIRTUAL_ENV__
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH:q"
|
||||
-setenv PATH "$VIRTUAL_ENV:q/__BIN_NAME__:$PATH:q"
|
||||
+setenv PATH "$VIRTUAL_ENV:q/"__BIN_NAME__":$PATH:q"
|
||||
|
||||
|
||||
|
||||
-if ('__VIRTUAL_PROMPT__' != "") then
|
||||
- set env_name = '(__VIRTUAL_PROMPT__) '
|
||||
+if (__VIRTUAL_PROMPT__ != "") then
|
||||
+ set env_name = __VIRTUAL_PROMPT__
|
||||
else
|
||||
set env_name = '('"$VIRTUAL_ENV:t:q"') '
|
||||
endif
|
||||
@@ -42,7 +42,7 @@ if ( $do_prompt == "1" ) then
|
||||
if ( "$prompt:q" =~ *"$newline:q"* ) then
|
||||
:
|
||||
else
|
||||
- set prompt = "$env_name:q$prompt:q"
|
||||
+ set prompt = '('"$env_name:q"') '"$prompt:q"
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
diff --git a/src/virtualenv/activation/fish/activate.fish b/src/virtualenv/activation/fish/activate.fish
|
||||
index 62f631e..3637d55 100644
|
||||
--- a/src/virtualenv/activation/fish/activate.fish
|
||||
+++ b/src/virtualenv/activation/fish/activate.fish
|
||||
@@ -57,7 +57,7 @@ end
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
-set -gx VIRTUAL_ENV '__VIRTUAL_ENV__'
|
||||
+set -gx VIRTUAL_ENV __VIRTUAL_ENV__
|
||||
|
||||
# https://github.com/fish-shell/fish-shell/issues/436 altered PATH handling
|
||||
if test (echo $FISH_VERSION | head -c 1) -lt 3
|
||||
@@ -65,7 +65,7 @@ if test (echo $FISH_VERSION | head -c 1) -lt 3
|
||||
else
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
end
|
||||
-set -gx PATH "$VIRTUAL_ENV"'/__BIN_NAME__' $PATH
|
||||
+set -gx PATH "$VIRTUAL_ENV"'/'__BIN_NAME__ $PATH
|
||||
|
||||
# Unset `$PYTHONHOME` if set.
|
||||
if set -q PYTHONHOME
|
||||
@@ -87,8 +87,8 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
|
||||
|
||||
# Prompt override provided?
|
||||
# If not, just prepend the environment name.
|
||||
- if test -n '__VIRTUAL_PROMPT__'
|
||||
- printf '(%s) ' '__VIRTUAL_PROMPT__'
|
||||
+ if test -n __VIRTUAL_PROMPT__
|
||||
+ printf '(%s) ' __VIRTUAL_PROMPT__
|
||||
else
|
||||
printf '(%s) ' (basename "$VIRTUAL_ENV")
|
||||
end
|
||||
diff --git a/src/virtualenv/activation/nushell/__init__.py b/src/virtualenv/activation/nushell/__init__.py
|
||||
index 4e2ea77..c96af22 100644
|
||||
--- a/src/virtualenv/activation/nushell/__init__.py
|
||||
+++ b/src/virtualenv/activation/nushell/__init__.py
|
||||
@@ -5,6 +5,25 @@ class NushellActivator(ViaTemplateActivator):
|
||||
def templates(self):
|
||||
yield "activate.nu"
|
||||
|
||||
+ @staticmethod
|
||||
+ def quote(string):
|
||||
+ """
|
||||
+ Nushell supports raw strings like: r###'this is a string'###.
|
||||
+
|
||||
+ This method finds the maximum continuous sharps in the string and then
|
||||
+ quote it with an extra sharp.
|
||||
+ """
|
||||
+ max_sharps = 0
|
||||
+ current_sharps = 0
|
||||
+ for char in string:
|
||||
+ if char == "#":
|
||||
+ current_sharps += 1
|
||||
+ max_sharps = max(current_sharps, max_sharps)
|
||||
+ else:
|
||||
+ current_sharps = 0
|
||||
+ wrapping = "#" * (max_sharps + 1)
|
||||
+ return f"r{wrapping}'{string}'{wrapping}"
|
||||
+
|
||||
def replacements(self, creator, dest_folder): # noqa: U100
|
||||
return {
|
||||
"__VIRTUAL_PROMPT__": "" if self.flag_prompt is None else self.flag_prompt,
|
||||
diff --git a/src/virtualenv/activation/nushell/activate.nu b/src/virtualenv/activation/nushell/activate.nu
|
||||
index 3da1519..569a8a1 100644
|
||||
--- a/src/virtualenv/activation/nushell/activate.nu
|
||||
+++ b/src/virtualenv/activation/nushell/activate.nu
|
||||
@@ -31,8 +31,8 @@ export-env {
|
||||
}
|
||||
|
||||
let is_windows = ($nu.os-info.name | str downcase) == 'windows'
|
||||
- let virtual_env = '__VIRTUAL_ENV__'
|
||||
- let bin = '__BIN_NAME__'
|
||||
+ let virtual_env = __VIRTUAL_ENV__
|
||||
+ let bin = __BIN_NAME__
|
||||
let path_sep = (char esep)
|
||||
let path_name = (if $is_windows {
|
||||
if (has-env 'Path') {
|
||||
@@ -73,10 +73,10 @@ export-env {
|
||||
$new_env
|
||||
} else {
|
||||
# Creating the new prompt for the session
|
||||
- let virtual_prompt = (if ('__VIRTUAL_PROMPT__' == '') {
|
||||
+ let virtual_prompt = (if (__VIRTUAL_PROMPT__ == '') {
|
||||
$'(char lparen)($virtual_env | path basename)(char rparen) '
|
||||
} else {
|
||||
- '(__VIRTUAL_PROMPT__) '
|
||||
+ (__VIRTUAL_PROMPT__)
|
||||
})
|
||||
|
||||
# Back up the old prompt builder
|
||||
diff --git a/src/virtualenv/activation/powershell/__init__.py b/src/virtualenv/activation/powershell/__init__.py
|
||||
index 4e74ecb..773d690 100644
|
||||
--- a/src/virtualenv/activation/powershell/__init__.py
|
||||
+++ b/src/virtualenv/activation/powershell/__init__.py
|
||||
@@ -5,6 +5,18 @@ class PowerShellActivator(ViaTemplateActivator):
|
||||
def templates(self):
|
||||
yield "activate.ps1"
|
||||
|
||||
+ @staticmethod
|
||||
+ def quote(string):
|
||||
+ """
|
||||
+ This should satisfy PowerShell quoting rules [1], unless the quoted
|
||||
+ string is passed directly to Windows native commands [2].
|
||||
+
|
||||
+ [1]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules
|
||||
+ [2]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing#passing-arguments-that-contain-quote-characters
|
||||
+ """ # noqa: D205
|
||||
+ string = string.replace("'", "''")
|
||||
+ return f"'{string}'"
|
||||
+
|
||||
|
||||
__all__ = [
|
||||
"PowerShellActivator",
|
||||
diff --git a/src/virtualenv/activation/powershell/activate.ps1 b/src/virtualenv/activation/powershell/activate.ps1
|
||||
index d524347..346980d 100644
|
||||
--- a/src/virtualenv/activation/powershell/activate.ps1
|
||||
+++ b/src/virtualenv/activation/powershell/activate.ps1
|
||||
@@ -35,18 +35,18 @@ $env:VIRTUAL_ENV = $VIRTUAL_ENV
|
||||
|
||||
New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH
|
||||
|
||||
-$env:PATH = "$env:VIRTUAL_ENV/__BIN_NAME____PATH_SEP__" + $env:PATH
|
||||
+$env:PATH = "$env:VIRTUAL_ENV/" + __BIN_NAME__ + __PATH_SEP__ + $env:PATH
|
||||
if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) {
|
||||
function global:_old_virtual_prompt {
|
||||
""
|
||||
}
|
||||
$function:_old_virtual_prompt = $function:prompt
|
||||
|
||||
- if ("__VIRTUAL_PROMPT__" -ne "") {
|
||||
+ if (__VIRTUAL_PROMPT__ -ne "") {
|
||||
function global:prompt {
|
||||
# Add the custom prefix to the existing prompt
|
||||
$previous_prompt_value = & $function:_old_virtual_prompt
|
||||
- ("(__VIRTUAL_PROMPT__) " + $previous_prompt_value)
|
||||
+ ((__VIRTUAL_PROMPT__) + $previous_prompt_value)
|
||||
}
|
||||
}
|
||||
else {
|
||||
diff --git a/src/virtualenv/activation/python/__init__.py b/src/virtualenv/activation/python/__init__.py
|
||||
index a49444b..8f0971e 100644
|
||||
--- a/src/virtualenv/activation/python/__init__.py
|
||||
+++ b/src/virtualenv/activation/python/__init__.py
|
||||
@@ -9,10 +9,14 @@ class PythonActivator(ViaTemplateActivator):
|
||||
def templates(self):
|
||||
yield "activate_this.py"
|
||||
|
||||
+ @staticmethod
|
||||
+ def quote(string):
|
||||
+ return repr(string)
|
||||
+
|
||||
def replacements(self, creator, dest_folder):
|
||||
replacements = super().replacements(creator, dest_folder)
|
||||
lib_folders = OrderedDict((os.path.relpath(str(i), str(dest_folder)), None) for i in creator.libs)
|
||||
- lib_folders = os.pathsep.join(lib_folders.keys()).replace("\\", "\\\\") # escape Windows path characters
|
||||
+ lib_folders = os.pathsep.join(lib_folders.keys())
|
||||
win_py2 = creator.interpreter.platform == "win32" and creator.interpreter.version_info.major == 2
|
||||
replacements.update(
|
||||
{
|
||||
diff --git a/src/virtualenv/activation/python/activate_this.py b/src/virtualenv/activation/python/activate_this.py
|
||||
index e8eeb84..976952e 100644
|
||||
--- a/src/virtualenv/activation/python/activate_this.py
|
||||
+++ b/src/virtualenv/activation/python/activate_this.py
|
||||
@@ -14,7 +14,7 @@ except NameError:
|
||||
raise AssertionError("You must use exec(open(this_file).read(), {'__file__': this_file}))")
|
||||
|
||||
bin_dir = os.path.dirname(abs_file)
|
||||
-base = bin_dir[: -len("__BIN_NAME__") - 1] # strip away the bin part from the __file__, plus the path separator
|
||||
+base = bin_dir[: -len(__BIN_NAME__) - 1] # strip away the bin part from the __file__, plus the path separator
|
||||
|
||||
# prepend bin to PATH (this file is inside the bin directory)
|
||||
os.environ["PATH"] = os.pathsep.join([bin_dir] + os.environ.get("PATH", "").split(os.pathsep))
|
||||
@@ -22,9 +22,9 @@ os.environ["VIRTUAL_ENV"] = base # virtual env is right above bin directory
|
||||
|
||||
# add the virtual environments libraries to the host python import mechanism
|
||||
prev_length = len(sys.path)
|
||||
-for lib in "__LIB_FOLDERS__".split(os.pathsep):
|
||||
+for lib in __LIB_FOLDERS__.split(os.pathsep):
|
||||
path = os.path.realpath(os.path.join(bin_dir, lib))
|
||||
- site.addsitedir(path.decode("utf-8") if "__DECODE_PATH__" else path)
|
||||
+ site.addsitedir(path.decode("utf-8") if __DECODE_PATH__ else path)
|
||||
sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length]
|
||||
|
||||
sys.real_prefix = sys.prefix
|
||||
diff --git a/src/virtualenv/activation/via_template.py b/src/virtualenv/activation/via_template.py
|
||||
index cc9dbda..b1dfa6b 100644
|
||||
--- a/src/virtualenv/activation/via_template.py
|
||||
+++ b/src/virtualenv/activation/via_template.py
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
+import shlex
|
||||
import sys
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
@@ -19,6 +20,16 @@ class ViaTemplateActivator(Activator, metaclass=ABCMeta):
|
||||
def templates(self):
|
||||
raise NotImplementedError
|
||||
|
||||
+ @staticmethod
|
||||
+ def quote(string):
|
||||
+ """
|
||||
+ Quote strings in the activation script.
|
||||
+
|
||||
+ :param string: the string to quote
|
||||
+ :return: quoted string that works in the activation script
|
||||
+ """
|
||||
+ return shlex.quote(string)
|
||||
+
|
||||
def generate(self, creator):
|
||||
dest_folder = creator.bin_dir
|
||||
replacements = self.replacements(creator, dest_folder)
|
||||
@@ -58,8 +69,8 @@ class ViaTemplateActivator(Activator, metaclass=ABCMeta):
|
||||
binary = read_binary(self.__module__, template)
|
||||
text = binary.decode("utf-8", errors="strict")
|
||||
for key, value in replacements.items():
|
||||
- value = self._repr_unicode(creator, value)
|
||||
- text = text.replace(key, value)
|
||||
+ value_uni = self._repr_unicode(creator, value)
|
||||
+ text = text.replace(key, self.quote(value_uni))
|
||||
return text
|
||||
|
||||
@staticmethod
|
||||
diff --git a/tests/conftest.py b/tests/conftest.py
|
||||
index a7ec4e0..b2fae66 100644
|
||||
--- a/tests/conftest.py
|
||||
+++ b/tests/conftest.py
|
||||
@@ -292,7 +292,11 @@ def is_inside_ci():
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def special_char_name():
|
||||
- base = "e-$ èрт🚒♞中片-j"
|
||||
+ base = "'\";&&e-$ èрт🚒♞中片-j"
|
||||
+ if IS_WIN:
|
||||
+ # get rid of invalid characters on Windows
|
||||
+ base = base.replace('"', "")
|
||||
+ base = base.replace(";", "")
|
||||
# workaround for pypy3 https://bitbucket.org/pypy/pypy/issues/3147/venv-non-ascii-support-windows
|
||||
encoding = "ascii" if IS_WIN else sys.getfilesystemencoding()
|
||||
# let's not include characters that the file system cannot encode)
|
||||
diff --git a/tests/unit/activation/conftest.py b/tests/unit/activation/conftest.py
|
||||
index e24a4fc..2d8b3ce 100644
|
||||
--- a/tests/unit/activation/conftest.py
|
||||
+++ b/tests/unit/activation/conftest.py
|
||||
@@ -4,7 +4,6 @@ import subprocess
|
||||
import sys
|
||||
from os.path import dirname, normcase
|
||||
from pathlib import Path
|
||||
-from shlex import quote
|
||||
from subprocess import Popen
|
||||
|
||||
import pytest
|
||||
@@ -146,7 +145,7 @@ class ActivationTester:
|
||||
assert out[-1] == "None", raw
|
||||
|
||||
def quote(self, s):
|
||||
- return quote(s)
|
||||
+ return self.of_class.quote(s)
|
||||
|
||||
def python_cmd(self, cmd):
|
||||
return f"{os.path.basename(sys.executable)} -c {self.quote(cmd)}"
|
||||
diff --git a/tests/unit/activation/test_batch.py b/tests/unit/activation/test_batch.py
|
||||
index 9e6d6d6..e95f7ea 100644
|
||||
--- a/tests/unit/activation/test_batch.py
|
||||
+++ b/tests/unit/activation/test_batch.py
|
||||
@@ -1,5 +1,3 @@
|
||||
-from shlex import quote
|
||||
-
|
||||
import pytest
|
||||
|
||||
from virtualenv.activation import BatchActivator
|
||||
@@ -25,10 +23,12 @@ def test_batch(activation_tester_class, activation_tester, tmp_path):
|
||||
return ["@echo off", "", "chcp 65001 1>NUL"] + super()._get_test_lines(activate_script)
|
||||
|
||||
def quote(self, s):
|
||||
- """double quotes needs to be single, and single need to be double"""
|
||||
- return "".join(("'" if c == '"' else ('"' if c == "'" else c)) for c in quote(s))
|
||||
+ if '"' in s or " " in s:
|
||||
+ text = s.replace('"', r"\"")
|
||||
+ return f'"{text}"'
|
||||
+ return s
|
||||
|
||||
def print_prompt(self):
|
||||
- return "echo %PROMPT%"
|
||||
+ return 'echo "%PROMPT%"'
|
||||
|
||||
activation_tester(Batch)
|
||||
diff --git a/tests/unit/activation/test_powershell.py b/tests/unit/activation/test_powershell.py
|
||||
index 761237f..f495353 100644
|
||||
--- a/tests/unit/activation/test_powershell.py
|
||||
+++ b/tests/unit/activation/test_powershell.py
|
||||
@@ -1,5 +1,4 @@
|
||||
import sys
|
||||
-from shlex import quote
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -19,10 +18,6 @@ def test_powershell(activation_tester_class, activation_tester, monkeypatch):
|
||||
self.activate_cmd = "."
|
||||
self.script_encoding = "utf-16"
|
||||
|
||||
- def quote(self, s):
|
||||
- """powershell double quote needed for quotes within single quotes"""
|
||||
- return quote(s).replace('"', '""')
|
||||
-
|
||||
def _get_test_lines(self, activate_script):
|
||||
# for BATCH utf-8 support need change the character code page to 650001
|
||||
return super()._get_test_lines(activate_script)
|
||||
@@ -33,4 +28,19 @@ def test_powershell(activation_tester_class, activation_tester, monkeypatch):
|
||||
def print_prompt(self):
|
||||
return "prompt"
|
||||
|
||||
+ def quote(self, s):
|
||||
+ """
|
||||
+ Tester will pass strings to native commands on Windows so extra
|
||||
+ parsing rules are used. Check `PowerShellActivator.quote` for more
|
||||
+ details.
|
||||
+ """
|
||||
+ text = PowerShellActivator.quote(s)
|
||||
+ return text.replace('"', '""') if sys.platform == "win32" else text
|
||||
+
|
||||
+ def activate_call(self, script):
|
||||
+ # Commands are called without quotes in PowerShell
|
||||
+ cmd = self.activate_cmd
|
||||
+ scr = self.quote(str(script))
|
||||
+ return f"{cmd} {scr}".strip()
|
||||
+
|
||||
activation_tester(PowerShell)
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,464 +0,0 @@
|
||||
From 71de653a714958d6649501b874009bafec74d3f4 Mon Sep 17 00:00:00 2001
|
||||
From: Philipp A <flying-sheep@web.de>
|
||||
Date: Tue, 23 Apr 2024 18:46:41 +0200
|
||||
Subject: [PATCH 1/2] Allow builtin interpreter discovery to find specific
|
||||
Python versions given a general spec (#2709)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Co-authored-by: Bernát Gábor <gaborjbernat@gmail.com>
|
||||
|
||||
Backported to 20.21.1 (without typing improvements).
|
||||
---
|
||||
docs/changelog/2709.bugfix.rst | 1 +
|
||||
src/virtualenv/discovery/builtin.py | 78 +++++++++++++-------------
|
||||
src/virtualenv/discovery/py_spec.py | 42 ++++++--------
|
||||
tests/unit/discovery/test_discovery.py | 15 ++++-
|
||||
4 files changed, 67 insertions(+), 69 deletions(-)
|
||||
create mode 100644 docs/changelog/2709.bugfix.rst
|
||||
|
||||
diff --git a/docs/changelog/2709.bugfix.rst b/docs/changelog/2709.bugfix.rst
|
||||
new file mode 100644
|
||||
index 0000000..904da84
|
||||
--- /dev/null
|
||||
+++ b/docs/changelog/2709.bugfix.rst
|
||||
@@ -0,0 +1 @@
|
||||
+allow builtin discovery to discover specific interpreters (e.g. ``python3.12``) given an unspecific spec (e.g. ``python3``) - by :user:`flying-sheep`.
|
||||
diff --git a/src/virtualenv/discovery/builtin.py b/src/virtualenv/discovery/builtin.py
|
||||
index 40320d3..f79b5a5 100644
|
||||
--- a/src/virtualenv/discovery/builtin.py
|
||||
+++ b/src/virtualenv/discovery/builtin.py
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
+from pathlib import Path
|
||||
|
||||
from virtualenv.info import IS_WIN
|
||||
|
||||
@@ -67,7 +68,7 @@ def get_interpreter(key, try_first_with, app_data=None, env=None):
|
||||
proposed_paths.add(key)
|
||||
|
||||
|
||||
-def propose_interpreters(spec, try_first_with, app_data, env=None):
|
||||
+def propose_interpreters(spec, try_first_with, app_data=None, env=None): # noqa: C901, PLR0912
|
||||
# 0. try with first
|
||||
env = os.environ if env is None else env
|
||||
for py_exe in try_first_with:
|
||||
@@ -101,20 +102,17 @@ def propose_interpreters(spec, try_first_with, app_data, env=None):
|
||||
for interpreter in propose_interpreters(spec, app_data, env):
|
||||
yield interpreter, True
|
||||
# finally just find on path, the path order matters (as the candidates are less easy to control by end user)
|
||||
- paths = get_paths(env)
|
||||
tested_exes = set()
|
||||
- for pos, path in enumerate(paths):
|
||||
- path_str = str(path)
|
||||
- logging.debug(LazyPathDump(pos, path_str, env))
|
||||
- for candidate, match in possible_specs(spec):
|
||||
- found = check_path(candidate, path_str)
|
||||
- if found is not None:
|
||||
- exe = os.path.abspath(found)
|
||||
- if exe not in tested_exes:
|
||||
- tested_exes.add(exe)
|
||||
- interpreter = PathPythonInfo.from_exe(exe, app_data, raise_on_error=False, env=env)
|
||||
- if interpreter is not None:
|
||||
- yield interpreter, match
|
||||
+ find_candidates = path_exe_finder(spec)
|
||||
+ for pos, path in enumerate(get_paths(env)):
|
||||
+ logging.debug(LazyPathDump(pos, path, env))
|
||||
+ for exe, impl_must_match in find_candidates(path):
|
||||
+ if exe in tested_exes:
|
||||
+ continue
|
||||
+ tested_exes.add(exe)
|
||||
+ interpreter = PathPythonInfo.from_exe(str(exe), app_data, raise_on_error=False, env=env)
|
||||
+ if interpreter is not None:
|
||||
+ yield interpreter, impl_must_match
|
||||
|
||||
|
||||
def get_paths(env):
|
||||
@@ -125,14 +123,14 @@ def get_paths(env):
|
||||
except (AttributeError, ValueError):
|
||||
path = os.defpath
|
||||
if not path:
|
||||
- paths = []
|
||||
- else:
|
||||
- paths = [p for p in path.split(os.pathsep) if os.path.exists(p)]
|
||||
- return paths
|
||||
+ return None
|
||||
+ for p in map(Path, path.split(os.pathsep)):
|
||||
+ if p.exists():
|
||||
+ yield p
|
||||
|
||||
|
||||
class LazyPathDump:
|
||||
- def __init__(self, pos, path, env):
|
||||
+ def __init__(self, pos, path, env) -> None:
|
||||
self.pos = pos
|
||||
self.path = path
|
||||
self.env = env
|
||||
@@ -141,35 +139,35 @@ class LazyPathDump:
|
||||
content = f"discover PATH[{self.pos}]={self.path}"
|
||||
if self.env.get("_VIRTUALENV_DEBUG"): # this is the over the board debug
|
||||
content += " with =>"
|
||||
- for file_name in os.listdir(self.path):
|
||||
+ for file_path in self.path.iterdir():
|
||||
try:
|
||||
- file_path = os.path.join(self.path, file_name)
|
||||
- if os.path.isdir(file_path) or not os.access(file_path, os.X_OK):
|
||||
+ if file_path.is_dir() or not (file_path.stat().st_mode & os.X_OK):
|
||||
continue
|
||||
except OSError:
|
||||
pass
|
||||
content += " "
|
||||
- content += file_name
|
||||
+ content += file_path.name
|
||||
return content
|
||||
|
||||
|
||||
-def check_path(candidate, path):
|
||||
- _, ext = os.path.splitext(candidate)
|
||||
- if sys.platform == "win32" and ext != ".exe":
|
||||
- candidate = candidate + ".exe"
|
||||
- if os.path.isfile(candidate):
|
||||
- return candidate
|
||||
- candidate = os.path.join(path, candidate)
|
||||
- if os.path.isfile(candidate):
|
||||
- return candidate
|
||||
- return None
|
||||
-
|
||||
-
|
||||
-def possible_specs(spec):
|
||||
- # 4. then maybe it's something exact on PATH - if it was direct lookup implementation no longer counts
|
||||
- yield spec.str_spec, False
|
||||
- # 5. or from the spec we can deduce a name on path that matches
|
||||
- yield from spec.generate_names()
|
||||
+def path_exe_finder(spec):
|
||||
+ """Given a spec, return a function that can be called on a path to find all matching files in it."""
|
||||
+ pat = spec.generate_re(windows=sys.platform == "win32")
|
||||
+ direct = spec.str_spec
|
||||
+ if sys.platform == "win32":
|
||||
+ direct = f"{direct}.exe"
|
||||
+
|
||||
+ def path_exes(path):
|
||||
+ # 4. then maybe it's something exact on PATH - if it was direct lookup implementation no longer counts
|
||||
+ yield (path / direct), False
|
||||
+ # 5. or from the spec we can deduce if a name on path matches
|
||||
+ for exe in path.iterdir():
|
||||
+ match = pat.fullmatch(exe.name)
|
||||
+ if match:
|
||||
+ # the implementation must match when we find “python[ver]”
|
||||
+ yield exe.absolute(), match["impl"] == "python"
|
||||
+
|
||||
+ return path_exes
|
||||
|
||||
|
||||
class PathPythonInfo(PythonInfo):
|
||||
diff --git a/src/virtualenv/discovery/py_spec.py b/src/virtualenv/discovery/py_spec.py
|
||||
index 103c7ae..cbfdfb8 100644
|
||||
--- a/src/virtualenv/discovery/py_spec.py
|
||||
+++ b/src/virtualenv/discovery/py_spec.py
|
||||
@@ -1,10 +1,9 @@
|
||||
"""A Python specification is an abstract requirement definition of an interpreter"""
|
||||
|
||||
+from __future__ import annotations
|
||||
+
|
||||
import os
|
||||
import re
|
||||
-from collections import OrderedDict
|
||||
-
|
||||
-from virtualenv.info import fs_is_case_sensitive
|
||||
|
||||
PATTERN = re.compile(r"^(?P<impl>[a-zA-Z]+)?(?P<version>[0-9.]+)?(?:-(?P<arch>32|64))?$")
|
||||
|
||||
@@ -12,7 +11,7 @@ PATTERN = re.compile(r"^(?P<impl>[a-zA-Z]+)?(?P<version>[0-9.]+)?(?:-(?P<arch>32
|
||||
class PythonSpec:
|
||||
"""Contains specification about a Python Interpreter"""
|
||||
|
||||
- def __init__(self, str_spec, implementation, major, minor, micro, architecture, path):
|
||||
+ def __init__(self, str_spec, implementation, major, minor, micro, architecture, path) -> None: # noqa: PLR0913
|
||||
self.str_spec = str_spec
|
||||
self.implementation = implementation
|
||||
self.major = major
|
||||
@@ -22,7 +21,7 @@ class PythonSpec:
|
||||
self.path = path
|
||||
|
||||
@classmethod
|
||||
- def from_string_spec(cls, string_spec):
|
||||
+ def from_string_spec(cls, string_spec): # noqa: C901, PLR0912
|
||||
impl, major, minor, micro, arch, path = None, None, None, None, None, None
|
||||
if os.path.isabs(string_spec):
|
||||
path = string_spec
|
||||
@@ -64,27 +63,18 @@ class PythonSpec:
|
||||
|
||||
return cls(string_spec, impl, major, minor, micro, arch, path)
|
||||
|
||||
- def generate_names(self):
|
||||
- impls = OrderedDict()
|
||||
- if self.implementation:
|
||||
- # first consider implementation as it is
|
||||
- impls[self.implementation] = False
|
||||
- if fs_is_case_sensitive():
|
||||
- # for case sensitive file systems consider lower and upper case versions too
|
||||
- # trivia: MacBooks and all pre 2018 Windows-es were case insensitive by default
|
||||
- impls[self.implementation.lower()] = False
|
||||
- impls[self.implementation.upper()] = False
|
||||
- impls["python"] = True # finally consider python as alias, implementation must match now
|
||||
- version = self.major, self.minor, self.micro
|
||||
- try:
|
||||
- version = version[: version.index(None)]
|
||||
- except ValueError:
|
||||
- pass
|
||||
- for impl, match in impls.items():
|
||||
- for at in range(len(version), -1, -1):
|
||||
- cur_ver = version[0:at]
|
||||
- spec = f"{impl}{'.'.join(str(i) for i in cur_ver)}"
|
||||
- yield spec, match
|
||||
+ def generate_re(self, *, windows):
|
||||
+ """Generate a regular expression for matching against a filename."""
|
||||
+ version = r"{}(\.{}(\.{})?)?".format(
|
||||
+ *(r"\d+" if v is None else v for v in (self.major, self.minor, self.micro))
|
||||
+ )
|
||||
+ impl = "python" if self.implementation is None else f"python|{re.escape(self.implementation)}"
|
||||
+ suffix = r"\.exe" if windows else ""
|
||||
+ # Try matching `direct` first, so the `direct` group is filled when possible.
|
||||
+ return re.compile(
|
||||
+ rf"(?P<impl>{impl})(?P<v>{version}){suffix}$",
|
||||
+ flags=re.IGNORECASE,
|
||||
+ )
|
||||
|
||||
@property
|
||||
def is_abs(self):
|
||||
diff --git a/tests/unit/discovery/test_discovery.py b/tests/unit/discovery/test_discovery.py
|
||||
index c4a2cc7..51bae24 100644
|
||||
--- a/tests/unit/discovery/test_discovery.py
|
||||
+++ b/tests/unit/discovery/test_discovery.py
|
||||
@@ -14,16 +14,25 @@ from virtualenv.info import fs_supports_symlink
|
||||
|
||||
@pytest.mark.skipif(not fs_supports_symlink(), reason="symlink not supported")
|
||||
@pytest.mark.parametrize("case", ["mixed", "lower", "upper"])
|
||||
-def test_discovery_via_path(monkeypatch, case, tmp_path, caplog, session_app_data):
|
||||
+@pytest.mark.parametrize("specificity", ["more", "less"])
|
||||
+def test_discovery_via_path(monkeypatch, case, specificity, tmp_path, caplog, session_app_data): # noqa: PLR0913
|
||||
caplog.set_level(logging.DEBUG)
|
||||
current = PythonInfo.current_system(session_app_data)
|
||||
- core = f"somethingVeryCryptic{'.'.join(str(i) for i in current.version_info[0:3])}"
|
||||
name = "somethingVeryCryptic"
|
||||
if case == "lower":
|
||||
name = name.lower()
|
||||
elif case == "upper":
|
||||
name = name.upper()
|
||||
- exe_name = f"{name}{current.version_info.major}{'.exe' if sys.platform == 'win32' else ''}"
|
||||
+ if specificity == "more":
|
||||
+ # e.g. spec: python3, exe: /bin/python3.12
|
||||
+ core_ver = current.version_info.major
|
||||
+ exe_ver = ".".join(str(i) for i in current.version_info[0:2])
|
||||
+ elif specificity == "less":
|
||||
+ # e.g. spec: python3.12.1, exe: /bin/python3
|
||||
+ core_ver = ".".join(str(i) for i in current.version_info[0:3])
|
||||
+ exe_ver = current.version_info.major
|
||||
+ core = f"somethingVeryCryptic{core_ver}"
|
||||
+ exe_name = f"{name}{exe_ver}{'.exe' if sys.platform == 'win32' else ''}"
|
||||
target = tmp_path / current.install_path("scripts")
|
||||
target.mkdir(parents=True)
|
||||
executable = target / exe_name
|
||||
--
|
||||
2.45.2
|
||||
|
||||
|
||||
From 4bb73d175614aa6041b1e9e57d7302b9c253b5ef Mon Sep 17 00:00:00 2001
|
||||
From: Ofek Lev <ofekmeister@gmail.com>
|
||||
Date: Sat, 27 Apr 2024 14:43:00 -0400
|
||||
Subject: [PATCH 2/2] Fix PATH-based Python discovery on Windows (#2712)
|
||||
|
||||
---
|
||||
docs/changelog/2712.bugfix.rst | 1 +
|
||||
src/virtualenv/discovery/builtin.py | 44 ++++++++++++++++++++------
|
||||
src/virtualenv/discovery/py_spec.py | 10 +++++-
|
||||
src/virtualenv/info.py | 5 +++
|
||||
tests/unit/discovery/test_discovery.py | 8 +++--
|
||||
5 files changed, 55 insertions(+), 13 deletions(-)
|
||||
create mode 100644 docs/changelog/2712.bugfix.rst
|
||||
|
||||
diff --git a/docs/changelog/2712.bugfix.rst b/docs/changelog/2712.bugfix.rst
|
||||
new file mode 100644
|
||||
index 0000000..fee5436
|
||||
--- /dev/null
|
||||
+++ b/docs/changelog/2712.bugfix.rst
|
||||
@@ -0,0 +1 @@
|
||||
+fix PATH-based Python discovery on Windows - by :user:`ofek`.
|
||||
diff --git a/src/virtualenv/discovery/builtin.py b/src/virtualenv/discovery/builtin.py
|
||||
index f79b5a5..456c68b 100644
|
||||
--- a/src/virtualenv/discovery/builtin.py
|
||||
+++ b/src/virtualenv/discovery/builtin.py
|
||||
@@ -3,7 +3,7 @@ import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
-from virtualenv.info import IS_WIN
|
||||
+from virtualenv.info import IS_WIN, fs_path_id
|
||||
|
||||
from .discover import Discover
|
||||
from .py_info import PythonInfo
|
||||
@@ -68,9 +68,10 @@ def get_interpreter(key, try_first_with, app_data=None, env=None):
|
||||
proposed_paths.add(key)
|
||||
|
||||
|
||||
-def propose_interpreters(spec, try_first_with, app_data=None, env=None): # noqa: C901, PLR0912
|
||||
+def propose_interpreters(spec, try_first_with, app_data=None, env=None): # noqa: C901, PLR0912, PLR0915
|
||||
# 0. try with first
|
||||
env = os.environ if env is None else env
|
||||
+ tested_exes: set[str] = set()
|
||||
for py_exe in try_first_with:
|
||||
path = os.path.abspath(py_exe)
|
||||
try:
|
||||
@@ -78,7 +79,12 @@ def propose_interpreters(spec, try_first_with, app_data=None, env=None): # noqa
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
- yield PythonInfo.from_exe(os.path.abspath(path), app_data, env=env), True
|
||||
+ exe_raw = os.path.abspath(path)
|
||||
+ exe_id = fs_path_id(exe_raw)
|
||||
+ if exe_id in tested_exes:
|
||||
+ continue
|
||||
+ tested_exes.add(exe_id)
|
||||
+ yield PythonInfo.from_exe(exe_raw, app_data, env=env), True
|
||||
|
||||
# 1. if it's a path and exists
|
||||
if spec.path is not None:
|
||||
@@ -88,29 +94,44 @@ def propose_interpreters(spec, try_first_with, app_data=None, env=None): # noqa
|
||||
if spec.is_abs:
|
||||
raise
|
||||
else:
|
||||
- yield PythonInfo.from_exe(os.path.abspath(spec.path), app_data, env=env), True
|
||||
+ exe_raw = os.path.abspath(spec.path)
|
||||
+ exe_id = fs_path_id(exe_raw)
|
||||
+ if exe_id not in tested_exes:
|
||||
+ tested_exes.add(exe_id)
|
||||
+ yield PythonInfo.from_exe(exe_raw, app_data, env=env), True
|
||||
if spec.is_abs:
|
||||
return
|
||||
else:
|
||||
# 2. otherwise try with the current
|
||||
- yield PythonInfo.current_system(app_data), True
|
||||
+ current_python = PythonInfo.current_system(app_data)
|
||||
+ exe_raw = str(current_python.executable)
|
||||
+ exe_id = fs_path_id(exe_raw)
|
||||
+ if exe_id not in tested_exes:
|
||||
+ tested_exes.add(exe_id)
|
||||
+ yield current_python, True
|
||||
|
||||
# 3. otherwise fallback to platform default logic
|
||||
if IS_WIN:
|
||||
from .windows import propose_interpreters
|
||||
|
||||
for interpreter in propose_interpreters(spec, app_data, env):
|
||||
+ exe_raw = str(interpreter.executable)
|
||||
+ exe_id = fs_path_id(exe_raw)
|
||||
+ if exe_id in tested_exes:
|
||||
+ continue
|
||||
+ tested_exes.add(exe_id)
|
||||
yield interpreter, True
|
||||
# finally just find on path, the path order matters (as the candidates are less easy to control by end user)
|
||||
- tested_exes = set()
|
||||
find_candidates = path_exe_finder(spec)
|
||||
for pos, path in enumerate(get_paths(env)):
|
||||
logging.debug(LazyPathDump(pos, path, env))
|
||||
for exe, impl_must_match in find_candidates(path):
|
||||
- if exe in tested_exes:
|
||||
+ exe_raw = str(exe)
|
||||
+ exe_id = fs_path_id(exe_raw)
|
||||
+ if exe_id in tested_exes:
|
||||
continue
|
||||
- tested_exes.add(exe)
|
||||
- interpreter = PathPythonInfo.from_exe(str(exe), app_data, raise_on_error=False, env=env)
|
||||
+ tested_exes.add(exe_id)
|
||||
+ interpreter = PathPythonInfo.from_exe(exe_raw, app_data, raise_on_error=False, env=env)
|
||||
if interpreter is not None:
|
||||
yield interpreter, impl_must_match
|
||||
|
||||
@@ -159,7 +180,10 @@ def path_exe_finder(spec):
|
||||
|
||||
def path_exes(path):
|
||||
# 4. then maybe it's something exact on PATH - if it was direct lookup implementation no longer counts
|
||||
- yield (path / direct), False
|
||||
+ direct_path = path / direct
|
||||
+ if direct_path.exists():
|
||||
+ yield direct_path, False
|
||||
+
|
||||
# 5. or from the spec we can deduce if a name on path matches
|
||||
for exe in path.iterdir():
|
||||
match = pat.fullmatch(exe.name)
|
||||
diff --git a/src/virtualenv/discovery/py_spec.py b/src/virtualenv/discovery/py_spec.py
|
||||
index cbfdfb8..04b63b8 100644
|
||||
--- a/src/virtualenv/discovery/py_spec.py
|
||||
+++ b/src/virtualenv/discovery/py_spec.py
|
||||
@@ -70,9 +70,17 @@ class PythonSpec:
|
||||
)
|
||||
impl = "python" if self.implementation is None else f"python|{re.escape(self.implementation)}"
|
||||
suffix = r"\.exe" if windows else ""
|
||||
+ version_conditional = (
|
||||
+ "?"
|
||||
+ # Windows Python executables are almost always unversioned
|
||||
+ if windows
|
||||
+ # Spec is an empty string
|
||||
+ or self.major is None
|
||||
+ else ""
|
||||
+ )
|
||||
# Try matching `direct` first, so the `direct` group is filled when possible.
|
||||
return re.compile(
|
||||
- rf"(?P<impl>{impl})(?P<v>{version}){suffix}$",
|
||||
+ rf"(?P<impl>{impl})(?P<v>{version}){version_conditional}{suffix}$",
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
|
||||
diff --git a/src/virtualenv/info.py b/src/virtualenv/info.py
|
||||
index a4fc4bf..dd96f10 100644
|
||||
--- a/src/virtualenv/info.py
|
||||
+++ b/src/virtualenv/info.py
|
||||
@@ -47,11 +47,16 @@ def fs_supports_symlink():
|
||||
return _CAN_SYMLINK
|
||||
|
||||
|
||||
+def fs_path_id(path: str) -> str:
|
||||
+ return path.casefold() if fs_is_case_sensitive() else path
|
||||
+
|
||||
+
|
||||
__all__ = (
|
||||
"IS_PYPY",
|
||||
"IS_CPYTHON",
|
||||
"IS_WIN",
|
||||
"fs_is_case_sensitive",
|
||||
+ "fs_path_id",
|
||||
"fs_supports_symlink",
|
||||
"ROOT",
|
||||
"IS_ZIPAPP",
|
||||
diff --git a/tests/unit/discovery/test_discovery.py b/tests/unit/discovery/test_discovery.py
|
||||
index 51bae24..6c64b40 100644
|
||||
--- a/tests/unit/discovery/test_discovery.py
|
||||
+++ b/tests/unit/discovery/test_discovery.py
|
||||
@@ -14,7 +14,7 @@ from virtualenv.info import fs_supports_symlink
|
||||
|
||||
@pytest.mark.skipif(not fs_supports_symlink(), reason="symlink not supported")
|
||||
@pytest.mark.parametrize("case", ["mixed", "lower", "upper"])
|
||||
-@pytest.mark.parametrize("specificity", ["more", "less"])
|
||||
+@pytest.mark.parametrize("specificity", ["more", "less", "none"])
|
||||
def test_discovery_via_path(monkeypatch, case, specificity, tmp_path, caplog, session_app_data): # noqa: PLR0913
|
||||
caplog.set_level(logging.DEBUG)
|
||||
current = PythonInfo.current_system(session_app_data)
|
||||
@@ -31,7 +31,11 @@ def test_discovery_via_path(monkeypatch, case, specificity, tmp_path, caplog, se
|
||||
# e.g. spec: python3.12.1, exe: /bin/python3
|
||||
core_ver = ".".join(str(i) for i in current.version_info[0:3])
|
||||
exe_ver = current.version_info.major
|
||||
- core = f"somethingVeryCryptic{core_ver}"
|
||||
+ elif specificity == "none":
|
||||
+ # e.g. spec: python3.12.1, exe: /bin/python
|
||||
+ core_ver = ".".join(str(i) for i in current.version_info[0:3])
|
||||
+ exe_ver = ""
|
||||
+ core = "" if specificity == "none" else f"{name}{core_ver}"
|
||||
exe_name = f"{name}{exe_ver}{'.exe' if sys.platform == 'win32' else ''}"
|
||||
target = tmp_path / current.install_path("scripts")
|
||||
target.mkdir(parents=True)
|
||||
--
|
||||
2.45.2
|
||||
|
@ -1,60 +0,0 @@
|
||||
From 11c30f6c69c4516b406c1c62f472d37898c58b93 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
|
||||
Date: Mon, 4 Dec 2023 14:26:52 +0100
|
||||
Subject: [PATCH] Run CI tests on Python 3.13, fix tests (#2673)
|
||||
|
||||
---
|
||||
docs/changelog/2673.feature.rst | 1 +
|
||||
tests/unit/create/test_creator.py | 6 +++++-
|
||||
tests/unit/create/via_global_ref/builtin/testing/path.py | 6 +++++-
|
||||
3 files changed, 11 insertions(+), 2 deletions(-)
|
||||
create mode 100644 docs/changelog/2673.feature.rst
|
||||
|
||||
diff --git a/docs/changelog/2673.feature.rst b/docs/changelog/2673.feature.rst
|
||||
new file mode 100644
|
||||
index 0000000..0adf4a0
|
||||
--- /dev/null
|
||||
+++ b/docs/changelog/2673.feature.rst
|
||||
@@ -0,0 +1 @@
|
||||
+The tests now pass on the CI with Python 3.13.0a2 - by :user:`hroncok`.
|
||||
diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py
|
||||
index 8b9d688..fc21ad8 100644
|
||||
--- a/tests/unit/create/test_creator.py
|
||||
+++ b/tests/unit/create/test_creator.py
|
||||
@@ -231,7 +231,11 @@ def test_create_no_seed(python, creator, isolated, system, coverage_env, special
|
||||
assert os.path.exists(make_file)
|
||||
|
||||
git_ignore = (dest / ".gitignore").read_text(encoding="utf-8")
|
||||
- assert git_ignore.splitlines() == ["# created by virtualenv automatically", "*"]
|
||||
+ if creator_key == "venv" and sys.version_info >= (3, 13):
|
||||
+ comment = "# Created by venv; see https://docs.python.org/3/library/venv.html"
|
||||
+ else:
|
||||
+ comment = "# created by virtualenv automatically"
|
||||
+ assert git_ignore.splitlines() == [comment, "*"]
|
||||
|
||||
|
||||
def test_create_vcs_ignore_exists(tmp_path):
|
||||
diff --git a/tests/unit/create/via_global_ref/builtin/testing/path.py b/tests/unit/create/via_global_ref/builtin/testing/path.py
|
||||
index b2e1b85..d833de6 100644
|
||||
--- a/tests/unit/create/via_global_ref/builtin/testing/path.py
|
||||
+++ b/tests/unit/create/via_global_ref/builtin/testing/path.py
|
||||
@@ -44,11 +44,15 @@ class PathMockABC(FakeDataABC, Path):
|
||||
"""Mocks the behavior of `Path`"""
|
||||
|
||||
_flavour = getattr(Path(), "_flavour", None)
|
||||
-
|
||||
if hasattr(_flavour, "altsep"):
|
||||
# Allows to pass some tests for Windows via PosixPath.
|
||||
_flavour.altsep = _flavour.altsep or "\\"
|
||||
|
||||
+ # Python 3.13 renamed _flavour to parser
|
||||
+ parser = getattr(Path(), "parser", None)
|
||||
+ if hasattr(parser, "altsep"):
|
||||
+ parser.altsep = parser.altsep or "\\"
|
||||
+
|
||||
def exists(self):
|
||||
return self.is_file() or self.is_dir()
|
||||
|
||||
--
|
||||
2.43.0
|
||||
|
@ -1,180 +0,0 @@
|
||||
%bcond bootstrap 0
|
||||
%bcond tests %{without bootstrap}
|
||||
|
||||
Name: python-virtualenv
|
||||
Version: 20.21.1
|
||||
Release: %autorelease
|
||||
Summary: Tool to create isolated Python environments
|
||||
|
||||
License: MIT
|
||||
URL: http://pypi.python.org/pypi/virtualenv
|
||||
Source0: %{pypi_source virtualenv}
|
||||
|
||||
# Add /usr/share/python-wheels to extra_search_dir
|
||||
Patch1: rpm-wheels.patch
|
||||
|
||||
## Backports from virtualenv 20.22+
|
||||
## We cannot update yet as we want to preserve support for Python 2.7 and 3.6 environments
|
||||
## Patches in https://github.com/fedora-python/virtualenv/commits/20.21.x
|
||||
# (20.23.0) prevent PermissionError when using venv creator on some systems
|
||||
# https://github.com/pypa/virtualenv/pull/2543
|
||||
Patch2: prevent-PermissionError-when-using-venv-creator-on-s.patch
|
||||
# (20.23.0) 3.12 support and no setuptools/wheel on 3.12+
|
||||
# freezgun and typing changes stripped
|
||||
# files missing in sdist removed from the path file
|
||||
# https://github.com/pypa/virtualenv/pull/2558
|
||||
Patch3: 3.12-support-and-no-setuptools-wheel-on-3.12-2558.patch
|
||||
# Fix compatibility with Python 3.13
|
||||
# https://github.com/pypa/virtualenv/pull/2673
|
||||
# https://github.com/pypa/virtualenv/pull/2702
|
||||
Patch5: py3.13.patch
|
||||
# Allow builtin interpreter discovery to find specific Python versions given a
|
||||
# general spec
|
||||
# https://github.com/pypa/virtualenv/pull/2709
|
||||
# which contains regressions (mostly but perhaps not exclusively on Windows)
|
||||
# that are fixed by:
|
||||
# Fix PATH-based Python discovery on Windows
|
||||
# https://github.com/pypa/virtualenv/pull/2712
|
||||
#
|
||||
# Backported to 20.21.1.
|
||||
Patch6: prs-2709-and-2712.patch
|
||||
# Quote template strings in activation scripts
|
||||
# to prevent possible command injection.
|
||||
# https://github.com/pypa/virtualenv/issues/2768
|
||||
# Backported from 20.26.6
|
||||
Patch7: prevent_command_injection.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: python3-devel
|
||||
|
||||
%if %{with tests}
|
||||
BuildRequires: fish
|
||||
BuildRequires: tcsh
|
||||
BuildRequires: gcc
|
||||
BuildRequires: python3-flaky
|
||||
BuildRequires: python3-packaging
|
||||
BuildRequires: python3-pytest
|
||||
BuildRequires: python3-pytest-mock
|
||||
BuildRequires: python3-pytest-randomly
|
||||
BuildRequires: python3-pytest-timeout
|
||||
%endif
|
||||
|
||||
# RPM installed wheels
|
||||
BuildRequires: %{python_wheel_pkg_prefix}-pip-wheel
|
||||
BuildRequires: %{python_wheel_pkg_prefix}-setuptools-wheel
|
||||
BuildRequires: %{python_wheel_pkg_prefix}-wheel-wheel
|
||||
|
||||
%description
|
||||
virtualenv is a tool to create isolated Python environments. virtualenv
|
||||
is a successor to workingenv, and an extension of virtual-python. It is
|
||||
written by Ian Bicking, and sponsored by the Open Planning Project. It is
|
||||
licensed under an MIT-style permissive license.
|
||||
|
||||
|
||||
%package -n python3-virtualenv
|
||||
Summary: Tool to create isolated Python environments
|
||||
|
||||
# This virtualenv requires the "venv" install scheme on Pythons
|
||||
# where we patch "posix_prefix".
|
||||
# Explicitly conflict with Pythons where we don't have it yet.
|
||||
Conflicts: python3.11 < 3.11.0~a2
|
||||
%if 0%{?fedora} >= 36
|
||||
Conflicts: python3.10 < 3.10.0-3
|
||||
%endif
|
||||
|
||||
Obsoletes: python3-virtualenv-python26 < 16.6
|
||||
%{?python_provide:%python_provide python3-virtualenv}
|
||||
|
||||
# Provide "virtualenv" for convenience
|
||||
Provides: virtualenv = %{version}-%{release}
|
||||
|
||||
# RPM installed wheels
|
||||
Requires: %{python_wheel_pkg_prefix}-pip-wheel
|
||||
Requires: %{python_wheel_pkg_prefix}-setuptools-wheel
|
||||
Requires: %{python_wheel_pkg_prefix}-wheel-wheel
|
||||
|
||||
# For Python 3.11
|
||||
Requires: (python3.11-pip-wheel if python3.11)
|
||||
Requires: (python3.11-setuptools-wheel if python3.11)
|
||||
Requires: (python3.11-wheel-wheel if python3.11)
|
||||
|
||||
# For Python 3.12
|
||||
# (setuptools and wheel is not installed by default, but still possible with --wheel/setuptools=bundle)
|
||||
Requires: (python3.12-pip-wheel if python3.12)
|
||||
Requires: (python3.12-setuptools-wheel if python3.12)
|
||||
Requires: (python3.12-wheel-wheel if python3.12)
|
||||
|
||||
%description -n python3-virtualenv
|
||||
virtualenv is a tool to create isolated Python environments. virtualenv
|
||||
is a successor to workingenv, and an extension of virtual-python. It is
|
||||
written by Ian Bicking, and sponsored by the Open Planning Project. It is
|
||||
licensed under an MIT-style permissive license
|
||||
|
||||
|
||||
%prep
|
||||
%autosetup -p1 -n virtualenv-%{version}
|
||||
|
||||
# Remove the wheels provided by RPM packages
|
||||
rm src/virtualenv/seed/wheels/embed/pip-*
|
||||
rm src/virtualenv/seed/wheels/embed/setuptools-*
|
||||
rm src/virtualenv/seed/wheels/embed/wheel-*
|
||||
|
||||
test ! -f src/virtualenv/seed/embed/wheels/*.whl
|
||||
|
||||
# Relax the upper bounds of some dependencies to their known available versions in EL 9
|
||||
# We run tests and CI to verify nothing broke
|
||||
sed -i -e 's/distlib<1,>=0.3.6/distlib<1,>=0.3.2/' \
|
||||
-e 's/filelock<4,>=3.4.1/filelock<4,>=3.3.1/' \
|
||||
-e 's/platformdirs<4,>=2.4/platformdirs<4,>=2.3/' \
|
||||
pyproject.toml
|
||||
|
||||
%generate_buildrequires
|
||||
%pyproject_buildrequires
|
||||
|
||||
%build
|
||||
%pyproject_wheel
|
||||
|
||||
%install
|
||||
%pyproject_install
|
||||
%pyproject_save_files virtualenv
|
||||
# EPEL 9: old version of setuptools_scm produces files incompatible with
|
||||
# assumptions in virtualenv code, we append the expected attributes:
|
||||
echo '__version__, __version_tuple__ = version, version_tuple' >> %{buildroot}%{python3_sitelib}/virtualenv/version.py
|
||||
|
||||
%if %{with tests}
|
||||
%check
|
||||
# Skip tests which requires internet or some extra dependencies
|
||||
# Requires internet:
|
||||
# - test_download_*
|
||||
# - test_can_build_c_extensions (on Python 3.12+)
|
||||
# Uses disabled functionalities around bundled wheels:
|
||||
# - test_wheel_*
|
||||
# - test_seed_link_via_app_data
|
||||
# - test_base_bootstrap_via_pip_invoke
|
||||
# - test_acquire.py (whole file)
|
||||
# - test_bundle.py (whole file)
|
||||
# Uses disabled functionalities around automatic updates:
|
||||
# - test_periodic_update.py (whole file)
|
||||
# Requires Python 2:
|
||||
# - test_py_pyc_missing
|
||||
PIP_CERT=/etc/pki/tls/certs/ca-bundle.crt \
|
||||
%pytest -vv -k "not test_bundle and \
|
||||
not test_acquire and \
|
||||
not test_periodic_update and \
|
||||
not test_wheel_ and \
|
||||
not test_download_ and \
|
||||
%if v"%{python3_version}" >= v"3.12"
|
||||
not test_can_build_c_extensions and \
|
||||
%endif
|
||||
not test_base_bootstrap_via_pip_invoke and \
|
||||
not test_seed_link_via_app_data and \
|
||||
not test_py_pyc_missing"
|
||||
%endif
|
||||
|
||||
%files -n python3-virtualenv -f %{pyproject_files}
|
||||
%doc README.md
|
||||
%{_bindir}/virtualenv
|
||||
|
||||
%changelog
|
||||
%autochangelog
|
@ -1,172 +0,0 @@
|
||||
From 3f22c840a0b26dae8dd09985501eaa33846f063c Mon Sep 17 00:00:00 2001
|
||||
From: Lumir Balhar <lbalhar@redhat.com>
|
||||
Date: Thu, 27 Oct 2022 11:50:54 +0200
|
||||
Subject: [PATCH] RPM wheels
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Co-Authored-By: Miro Hrončok <miro@hroncok.cz>
|
||||
---
|
||||
src/virtualenv/run/__init__.py | 5 ++--
|
||||
src/virtualenv/seed/embed/base_embed.py | 16 ++++++++++-
|
||||
src/virtualenv/seed/embed/pip_invoke.py | 1 +
|
||||
.../seed/embed/via_app_data/via_app_data.py | 1 +
|
||||
src/virtualenv/seed/wheels/acquire.py | 3 ++-
|
||||
src/virtualenv/seed/wheels/embed/__init__.py | 3 +++
|
||||
src/virtualenv/util/path/_system_wheels.py | 27 +++++++++++++++++++
|
||||
7 files changed, 52 insertions(+), 4 deletions(-)
|
||||
create mode 100644 src/virtualenv/util/path/_system_wheels.py
|
||||
|
||||
diff --git a/src/virtualenv/run/__init__.py b/src/virtualenv/run/__init__.py
|
||||
index 6d22b71..19d1791 100644
|
||||
--- a/src/virtualenv/run/__init__.py
|
||||
+++ b/src/virtualenv/run/__init__.py
|
||||
@@ -87,8 +87,9 @@ def build_parser_only(args=None):
|
||||
|
||||
def handle_extra_commands(options):
|
||||
if options.upgrade_embed_wheels:
|
||||
- result = manual_upgrade(options.app_data, options.env)
|
||||
- raise SystemExit(result)
|
||||
+ # result = manual_upgrade(options.app_data, options.env)
|
||||
+ logging.warning("virtualenv installed from the RPM package uses wheels from RPM packages as well. Updating them via virtualenv is not possible. The RPM packaged wheels are updated together with other RPM packages of the system.")
|
||||
+ raise SystemExit(1)
|
||||
|
||||
|
||||
def load_app_data(args, parser, options):
|
||||
diff --git a/src/virtualenv/seed/embed/base_embed.py b/src/virtualenv/seed/embed/base_embed.py
|
||||
index f29110b..07649c2 100644
|
||||
--- a/src/virtualenv/seed/embed/base_embed.py
|
||||
+++ b/src/virtualenv/seed/embed/base_embed.py
|
||||
@@ -3,8 +3,9 @@ from pathlib import Path
|
||||
|
||||
from ..seeder import Seeder
|
||||
from ..wheels import Version
|
||||
+from virtualenv.util.path._system_wheels import get_system_wheels_paths
|
||||
|
||||
-PERIODIC_UPDATE_ON_BY_DEFAULT = True
|
||||
+PERIODIC_UPDATE_ON_BY_DEFAULT = False
|
||||
|
||||
|
||||
class BaseEmbed(Seeder, metaclass=ABCMeta):
|
||||
@@ -27,6 +28,15 @@ class BaseEmbed(Seeder, metaclass=ABCMeta):
|
||||
if not self.distribution_to_versions():
|
||||
self.enabled = False
|
||||
|
||||
+ if "embed" in (self.pip_version, self.setuptools_version, self.wheel_version):
|
||||
+ raise RuntimeError(
|
||||
+ "Embedded wheels are not available if virtualenv "
|
||||
+ "is installed from the RPM package.\nEither install "
|
||||
+ "virtualenv from PyPI (via pip) or use 'bundle' "
|
||||
+ "version which uses the system-wide pip, setuptools "
|
||||
+ "and wheel wheels provided also by RPM packages."
|
||||
+ )
|
||||
+
|
||||
@classmethod
|
||||
def distributions(cls):
|
||||
return {
|
||||
@@ -105,6 +115,10 @@ class BaseEmbed(Seeder, metaclass=ABCMeta):
|
||||
result += f" {distribution}{ver},"
|
||||
return result[:-1] + ")"
|
||||
|
||||
+ def insert_system_wheels_paths(self, creator):
|
||||
+ system_wheels_paths = get_system_wheels_paths(creator.interpreter)
|
||||
+ self.extra_search_dir = list(system_wheels_paths) + self.extra_search_dir
|
||||
+
|
||||
|
||||
__all__ = [
|
||||
"BaseEmbed",
|
||||
diff --git a/src/virtualenv/seed/embed/pip_invoke.py b/src/virtualenv/seed/embed/pip_invoke.py
|
||||
index 2ca9438..339295f 100644
|
||||
--- a/src/virtualenv/seed/embed/pip_invoke.py
|
||||
+++ b/src/virtualenv/seed/embed/pip_invoke.py
|
||||
@@ -15,6 +15,7 @@ class PipInvoke(BaseEmbed):
|
||||
def run(self, creator):
|
||||
if not self.enabled:
|
||||
return
|
||||
+ self.insert_system_wheels_paths(creator)
|
||||
for_py_version = creator.interpreter.version_release_str
|
||||
with self.get_pip_install_cmd(creator.exe, for_py_version) as cmd:
|
||||
env = pip_wheel_env_run(self.extra_search_dir, self.app_data, self.env)
|
||||
diff --git a/src/virtualenv/seed/embed/via_app_data/via_app_data.py b/src/virtualenv/seed/embed/via_app_data/via_app_data.py
|
||||
index f31ecf6..d7a0f5a 100644
|
||||
--- a/src/virtualenv/seed/embed/via_app_data/via_app_data.py
|
||||
+++ b/src/virtualenv/seed/embed/via_app_data/via_app_data.py
|
||||
@@ -37,6 +37,7 @@ class FromAppData(BaseEmbed):
|
||||
def run(self, creator):
|
||||
if not self.enabled:
|
||||
return
|
||||
+ self.insert_system_wheels_paths(creator)
|
||||
with self._get_seed_wheels(creator) as name_to_whl:
|
||||
pip_version = name_to_whl["pip"].version_tuple if "pip" in name_to_whl else None
|
||||
installer_class = self.installer_class(pip_version)
|
||||
diff --git a/src/virtualenv/seed/wheels/acquire.py b/src/virtualenv/seed/wheels/acquire.py
|
||||
index 21fde34..4370b0d 100644
|
||||
--- a/src/virtualenv/seed/wheels/acquire.py
|
||||
+++ b/src/virtualenv/seed/wheels/acquire.py
|
||||
@@ -24,11 +24,12 @@ def get_wheel(distribution, version, for_py_version, search_dirs, download, app_
|
||||
|
||||
if download and wheel is None and version != Version.embed:
|
||||
# 2. download from the internet
|
||||
+ from virtualenv.util.path._system_wheels import get_system_wheels_paths
|
||||
wheel = download_wheel(
|
||||
distribution=distribution,
|
||||
version_spec=Version.as_version_spec(version),
|
||||
for_py_version=for_py_version,
|
||||
- search_dirs=search_dirs,
|
||||
+ search_dirs=get_system_wheels_paths(sys),
|
||||
app_data=app_data,
|
||||
to_folder=app_data.house,
|
||||
env=env,
|
||||
diff --git a/src/virtualenv/seed/wheels/embed/__init__.py b/src/virtualenv/seed/wheels/embed/__init__.py
|
||||
index 782051a..71ec712 100644
|
||||
--- a/src/virtualenv/seed/wheels/embed/__init__.py
|
||||
+++ b/src/virtualenv/seed/wheels/embed/__init__.py
|
||||
@@ -52,8 +52,11 @@ BUNDLE_SUPPORT = {
|
||||
}
|
||||
MAX = "3.12"
|
||||
|
||||
+# Redefined here because bundled wheels are removed in RPM build
|
||||
+BUNDLE_SUPPORT = None
|
||||
|
||||
def get_embed_wheel(distribution, for_py_version):
|
||||
+ return None # BUNDLE_SUPPORT == None anyway
|
||||
path = BUNDLE_FOLDER / (BUNDLE_SUPPORT.get(for_py_version, {}) or BUNDLE_SUPPORT[MAX]).get(distribution)
|
||||
return Wheel.from_path(path)
|
||||
|
||||
diff --git a/src/virtualenv/util/path/_system_wheels.py b/src/virtualenv/util/path/_system_wheels.py
|
||||
new file mode 100644
|
||||
index 0000000..fc7e942
|
||||
--- /dev/null
|
||||
+++ b/src/virtualenv/util/path/_system_wheels.py
|
||||
@@ -0,0 +1,27 @@
|
||||
+from pathlib import Path
|
||||
+from subprocess import check_output, CalledProcessError
|
||||
+
|
||||
+
|
||||
+def get_system_wheels_paths(interpreter):
|
||||
+ # ensurepip wheels
|
||||
+ # We need subprocess here to check ensurepip with the Python we are creating
|
||||
+ # a new virtual environment for
|
||||
+ executable = interpreter.executable
|
||||
+ try:
|
||||
+ ensurepip_path = check_output((executable, "-u", "-c", 'import ensurepip; print(ensurepip.__path__[0])'), universal_newlines=True)
|
||||
+ ensurepip_path = Path(ensurepip_path.strip()) / "_bundled"
|
||||
+ except CalledProcessError:
|
||||
+ pass
|
||||
+ else:
|
||||
+ if ensurepip_path.is_dir():
|
||||
+ yield ensurepip_path
|
||||
+
|
||||
+ # Standard wheels path
|
||||
+ # The EL 9 main Python has just 3 (this is the %{python3_pkgversion} RPM macro)
|
||||
+ if interpreter.version_info[:2] == (3, 9):
|
||||
+ python3_pkgversion = "3"
|
||||
+ else:
|
||||
+ python3_pkgversion = "{0.major}.{0.minor}".format(interpreter.version_info)
|
||||
+ wheels_dir = Path(f"/usr/share/python{python3_pkgversion}-wheels")
|
||||
+ if wheels_dir.exists():
|
||||
+ yield wheels_dir
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1 +0,0 @@
|
||||
SHA512 (virtualenv-20.21.1.tar.gz) = 5f5c4ce677feffe24b87ff4b3837e6f7cda6a5017eea122ac089be2066b74c7eaf452dbc0ab7723e9433716aeca13e6f85ea23d02fb28a83d76df5db0068572a
|
@ -1,57 +0,0 @@
|
||||
---
|
||||
- hosts: localhost
|
||||
roles:
|
||||
- role: standard-test-basic
|
||||
tags:
|
||||
- classic
|
||||
repositories:
|
||||
- repo: "https://src.fedoraproject.org/tests/python.git"
|
||||
dest: "python"
|
||||
tests:
|
||||
- smoke39:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.9 METHOD=virtualenv ./venv.sh
|
||||
- smoke39nd:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.9 METHOD=virtualenv-no-download ./venv.sh
|
||||
- smoke39d:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.9 METHOD=virtualenv-download TOX=false ./venv.sh
|
||||
- smoke39sp:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.9 METHOD=virtualenv-seeder-pip ./venv.sh
|
||||
- smoke311:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.11 METHOD=virtualenv ./venv.sh
|
||||
- smoke311d:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.11 METHOD=virtualenv-download TOX=false ./venv.sh
|
||||
- smoke311nd:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.11 METHOD=virtualenv-no-download ./venv.sh
|
||||
- smoke311sp:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.11 METHOD=virtualenv-seeder-pip ./venv.sh
|
||||
- smoke312:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.12 METHOD=virtualenv ./venv.sh
|
||||
- smoke312d:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.12 METHOD=virtualenv-download TOX=false ./venv.sh
|
||||
- smoke312nd:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.12 METHOD=virtualenv-no-download ./venv.sh
|
||||
- smoke312sp:
|
||||
dir: python/smoke
|
||||
run: VERSION=3.12 METHOD=virtualenv-seeder-pip ./venv.sh
|
||||
- rpm_qa:
|
||||
run: rpm -qa | sort
|
||||
required_packages:
|
||||
- gcc
|
||||
- virtualenv
|
||||
- python3.9
|
||||
- python3.11-devel
|
||||
- python3.12-devel
|
||||
- python3-devel
|
||||
- python3-tox
|
||||
- rpm
|
Loading…
Reference in new issue