diff --git a/_multibuild b/_multibuild
new file mode 100644
index 0000000..73ab5e8
--- /dev/null
+++ b/_multibuild
@@ -0,0 +1,5 @@
+
+ test-py38
+ test-py39
+ test-py310
+
diff --git a/artifacts.tar.gz b/artifacts.tar.gz
deleted file mode 100644
index f59438d..0000000
--- a/artifacts.tar.gz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fe8f3f8ccae277a91ec58cd95ee4fc69f12f346747c2f49fd85a14ddfeba89ba
-size 2925222
diff --git a/mark-network-tests.patch b/mark-network-tests.patch
deleted file mode 100644
index c8cd3c5..0000000
--- a/mark-network-tests.patch
+++ /dev/null
@@ -1,670 +0,0 @@
-From 01192dca2cc4aa3b6770c7672d1887e872772702 Mon Sep 17 00:00:00 2001
-From: Frost Ming
-Date: Fri, 21 Jan 2022 19:13:20 +0800
-Subject: [PATCH 1/3] Reduce the number of tests that require network
-
----
- news/858.misc.md | 1
- pdm/installers/synchronizers.py | 9 -
- pdm/utils.py | 10 -
- pyproject.toml | 5
- tests/cli/test_build.py | 29 +----
- tests/cli/test_install.py | 6 -
- tests/cli/test_others.py | 10 +
- tests/cli/test_run.py | 25 +---
- tests/cli/test_update.py | 1
- tests/conftest.py | 48 +++++---
- tests/fixtures/projects/demo-failure/setup.py | 2
- tests/fixtures/pypi.json | 1
- tests/models/test_candidates.py | 20 ++-
- tests/test_installer.py | 2
- tests/test_integration.py | 13 +-
- tests/test_project.py | 58 ++++------
- 27 files changed, 154 insertions(+), 119 deletions(-)
-
---- /dev/null
-+++ b/news/858.misc.md
-@@ -0,0 +1 @@
-+Reduce the number of tests that require network, and mark the rest with `network` marker.
---- a/pdm/installers/synchronizers.py
-+++ b/pdm/installers/synchronizers.py
-@@ -61,13 +61,8 @@ class DummyExecutor:
-
- def editables_candidate(environment: Environment) -> Candidate | None:
- """Return a candidate for `editables` package"""
-- with environment.get_finder() as finder:
-- best_match = finder.find_best_candidate("editables")
-- if best_match.best_candidate is None:
-- return None
-- return Candidate.from_installation_candidate(
-- best_match.best_candidate, parse_requirement("editables"), environment
-- )
-+ repository = environment.project.get_repository()
-+ return next(iter(repository.find_candidates(parse_requirement("editables"))), None)
-
-
- class Synchronizer:
---- a/pdm/utils.py
-+++ b/pdm/utils.py
-@@ -332,16 +332,6 @@ def cd(path: str | Path) -> Iterator:
-
-
- @contextmanager
--def temp_environ() -> Iterator:
-- environ = os.environ.copy()
-- try:
-- yield
-- finally:
-- os.environ.clear()
-- os.environ.update(environ)
--
--
--@contextmanager
- def open_file(url: str, session: Session | None = None) -> Iterator[BinaryIO]:
- if url.startswith("file://"):
- local_path = url_to_path(url)
---- a/pyproject.toml
-+++ b/pyproject.toml
-@@ -126,7 +126,10 @@ colorama = []
-
- [tool.pytest.ini_options]
- filterwarnings = [ "ignore::DeprecationWarning",]
--markers = [ "pypi: Tests that connect to the real PyPI", "integration: Run with all Python versions",]
-+markers = [
-+ "network: Tests that require network",
-+ "integration: Run with all Python versions",
-+]
- addopts = "-ra"
-
- [tool.pdm.scripts.doc]
---- a/tests/cli/test_build.py
-+++ b/tests/cli/test_build.py
-@@ -1,13 +1,12 @@
- import os
--import subprocess
--import sys
- import tarfile
- import zipfile
-
- import pytest
-
- from pdm.cli import actions
--from pdm.utils import temp_environ
-+
-+pytestmark = pytest.mark.usefixtures("local_finder")
-
-
- def get_tarball_names(path):
-@@ -170,22 +169,9 @@ def test_cli_build_with_config_settings(
- @pytest.mark.parametrize("isolated", (True, False))
- def test_build_with_no_isolation(fixture_project, invoke, isolated):
- project = fixture_project("demo-failure")
-- lib_path = project.environment.get_paths()["purelib"]
-- subprocess.run(
-- [
-- sys.executable,
-- "-m",
-- "pip",
-- "install",
-- "-I",
-- "--force-reinstall",
-- "idna",
-- "--target",
-- str(lib_path),
-- ],
-- check=True,
-- )
-- invoke(["add", "idna"], obj=project)
-+ project.pyproject = {"project": {"name": "demo", "version": "0.1.0"}}
-+ project.write_pyproject()
-+ invoke(["add", "first"], obj=project)
- args = ["build"]
- if not isolated:
- args.append("--no-isolation")
-@@ -195,6 +181,5 @@ def test_build_with_no_isolation(fixture
-
- def test_build_ignoring_pip_environment(fixture_project):
- project = fixture_project("demo-module")
-- with temp_environ():
-- os.environ["PIP_REQUIRE_VIRTUALENV"] = "1"
-- actions.do_build(project)
-+ os.environ["PIP_REQUIRE_VIRTUALENV"] = "1"
-+ actions.do_build(project)
---- a/tests/cli/test_install.py
-+++ b/tests/cli/test_install.py
-@@ -128,8 +128,8 @@ def test_sync_with_index_change(project,
-
-
- future-fstrings
--
-+
- future_fstrings-1.2.0.tar.gz
-
-
-@@ -138,7 +138,7 @@ def test_sync_with_index_change(project,
- actions.do_lock(project)
- file_hashes = project.lockfile["metadata"]["files"]["future-fstrings 1.2.0"]
- assert [e["hash"] for e in file_hashes] == [
-- "sha256:6cf41cbe97c398ab5a81168ce0dbb8ad95862d3caf23c21e4430627b90844089"
-+ "sha256:90e49598b553d8746c4dc7d9442e0359d038c3039d802c91c0a55505da318c63"
- ]
- # Mimic the CDN inconsistences of PyPI simple index. See issues/596.
- del index["future-fstrings"]
---- a/tests/cli/test_others.py
-+++ b/tests/cli/test_others.py
-@@ -19,6 +19,7 @@ def test_lock_dependencies(project):
- assert package in locked
-
-
-+@pytest.mark.usefixtures("project_no_init", "local_finder")
- def test_build_distributions(tmp_path, core):
- project = core.create_project()
- actions.do_build(project, dest=tmp_path.as_posix())
-@@ -251,14 +252,14 @@ def test_import_requirement_no_overwrite
- assert list(project.get_dependencies("web")) == ["flask", "flask-login"]
-
-
--@pytest.mark.pypi
--def test_search_package(project, invoke):
-- result = invoke(["search", "requests"], obj=project)
-+@pytest.mark.network
-+def test_search_package(invoke):
-+ result = invoke(["search", "requests"])
- assert result.exit_code == 0
- assert len(result.output.splitlines()) > 0
-
-
--@pytest.mark.pypi
-+@pytest.mark.network
- def test_show_package_on_pypi(invoke):
- result = invoke(["show", "ipython"])
- assert result.exit_code == 0
-@@ -344,6 +345,7 @@ def test_lock_refresh(invoke, project, r
- assert project.is_lockfile_hash_match()
-
-
-+@pytest.mark.network
- def test_show_update_hint(invoke, project):
- prev_version = project.core.version
- try:
---- a/tests/cli/test_run.py
-+++ b/tests/cli/test_run.py
-@@ -5,20 +5,15 @@ import textwrap
- from pathlib import Path
- from tempfile import TemporaryDirectory
-
--import pytest
--
- from pdm.cli.actions import PEP582_PATH
--from pdm.utils import cd, temp_environ
-+from pdm.utils import cd
-
-
--@pytest.mark.pypi
--def test_pep582_launcher_for_python_interpreter(project, invoke):
-- project.meta["requires-python"] = ">=3.6"
-- project.write_pyproject()
-+def test_pep582_launcher_for_python_interpreter(project, local_finder, invoke):
- project.root.joinpath("main.py").write_text(
-- "import requests\nprint(requests.__version__)\n"
-+ "import first;print(first.first([0, False, 1, 2]))\n"
- )
-- result = invoke(["add", "requests==2.24.0"], obj=project)
-+ result = invoke(["add", "first"], obj=project)
- assert result.exit_code == 0, result.stderr
- env = os.environ.copy()
- env.update({"PYTHONPATH": PEP582_PATH})
-@@ -26,7 +21,7 @@ def test_pep582_launcher_for_python_inte
- [project.python.executable, str(project.root.joinpath("main.py"))],
- env=env,
- )
-- assert output.decode().strip() == "2.24.0"
-+ assert output.decode().strip() == "1"
-
-
- def test_auto_isolate_site_packages(project, invoke):
-@@ -167,7 +162,7 @@ def test_run_expand_env_vars(project, in
- }
- project.write_pyproject()
- capfd.readouterr()
-- with cd(project.root), temp_environ():
-+ with cd(project.root):
- os.environ["FOO"] = "bar"
- invoke(["run", "test_cmd"], obj=project)
- assert capfd.readouterr()[0].strip() == "1"
-@@ -243,20 +238,20 @@ def test_run_show_list_of_scripts(projec
- assert result_lines[2].strip() == "test_shell shell echo $FOO shell command"
-
-
--def test_run_with_another_project_root(project, invoke, capfd):
-+def test_run_with_another_project_root(project, local_finder, invoke, capfd):
- project.meta["requires-python"] = ">=3.6"
- project.write_pyproject()
-- invoke(["add", "requests==2.24.0"], obj=project)
-+ invoke(["add", "first"], obj=project)
- with TemporaryDirectory(prefix="pytest-run-") as tmp_dir:
- Path(tmp_dir).joinpath("main.py").write_text(
-- "import requests\nprint(requests.__version__)\n"
-+ "import first;print(first.first([0, False, 1, 2]))\n"
- )
- capfd.readouterr()
- with cd(tmp_dir):
- ret = invoke(["run", "-p", str(project.root), "python", "main.py"])
- assert ret.exit_code == 0
- out, _ = capfd.readouterr()
-- assert out.strip() == "2.24.0"
-+ assert out.strip() == "1"
-
-
- def test_import_another_sitecustomize(project, invoke, capfd):
---- a/tests/cli/test_update.py
-+++ b/tests/cli/test_update.py
-@@ -164,6 +164,7 @@ def test_update_with_package_and_groups_
- actions.do_update(project, default=False, packages=("requests",))
-
-
-+@pytest.mark.usefixtures("repository", "working_set")
- def test_update_with_prerelease_without_package_argument(project):
- actions.do_add(project, packages=["requests"])
- with pytest.raises(
---- a/tests/conftest.py
-+++ b/tests/conftest.py
-@@ -4,6 +4,7 @@ import os
- import re
- import shutil
- import sys
-+from contextlib import contextmanager
- from io import BytesIO
- from pathlib import Path
- from typing import Callable, Dict, Iterable, List, Optional, Tuple
-@@ -28,11 +29,20 @@ from pdm.models.requirements import (
- )
- from pdm.project import Project
- from pdm.project.config import Config
--from pdm.utils import get_finder, normalize_name, temp_environ
-+from pdm.utils import get_finder, normalize_name
- from tests import FIXTURES
-
- os.environ["CI"] = "1"
--main = Core()
-+
-+
-+@contextmanager
-+def temp_environ():
-+ environ = os.environ.copy()
-+ try:
-+ yield
-+ finally:
-+ os.environ.clear()
-+ os.environ.update(environ)
-
-
- class LocalFileAdapter(requests.adapters.BaseAdapter):
-@@ -148,9 +158,6 @@ class TestProject(Project):
- super().__init__(core, root_path, is_global)
-
-
--main.project_class = TestProject
--
--
- class Distribution:
- def __init__(self, key, version, editable=False):
- self.version = version
-@@ -243,12 +250,19 @@ def remove_pep582_path_from_pythonpath(p
- return os.pathsep.join(paths)
-
-
-+@pytest.fixture(scope="session")
-+def core():
-+ main = Core()
-+ main.project_class = TestProject
-+ return main
-+
-+
- @pytest.fixture()
--def project_no_init(tmp_path, mocker):
-- p = main.create_project(tmp_path)
-+def project_no_init(tmp_path, mocker, core):
-+ p = core.create_project(tmp_path)
-+ mocker.patch("pdm.project.core.Config.HOME_CONFIG", tmp_path)
- mocker.patch("pdm.utils.get_finder", get_local_finder)
- mocker.patch("pdm.models.environment.get_finder", get_local_finder)
-- mocker.patch("pdm.project.core.Config.HOME_CONFIG", tmp_path)
- old_config_map = Config._config_map.copy()
- tmp_path.joinpath("caches").mkdir(parents=True)
- p.global_config["cache_dir"] = tmp_path.joinpath("caches").as_posix()
-@@ -268,6 +282,13 @@ def project_no_init(tmp_path, mocker):
-
-
- @pytest.fixture()
-+def local_finder(project_no_init, mocker):
-+ return_value = ["--no-index", "--find-links", str(FIXTURES / "artifacts")]
-+ mocker.patch("pdm.utils.prepare_pip_source_args", return_value=return_value)
-+ mocker.patch("pdm.builders.base.prepare_pip_source_args", return_value=return_value)
-+
-+
-+@pytest.fixture()
- def project(project_no_init):
- do_init(project_no_init, "test_project", "0.0.0")
- # Clean the cached property
-@@ -299,7 +320,7 @@ def fixture_project(project_no_init):
-
-
- @pytest.fixture()
--def repository(project, mocker):
-+def repository(project, mocker, local_finder):
- rv = TestRepository([], project.environment)
- mocker.patch.object(project, "get_repository", return_value=rv)
- return rv
-@@ -329,12 +350,12 @@ def is_dev(request):
-
-
- @pytest.fixture()
--def invoke():
-+def invoke(core):
- runner = CliRunner(mix_stderr=False)
-
- def caller(args, strict=False, **kwargs):
- result = runner.invoke(
-- main, args, catch_exceptions=not strict, prog_name="pdm", **kwargs
-+ core, args, catch_exceptions=not strict, prog_name="pdm", **kwargs
- )
- if strict and result.exit_code != 0:
- raise RuntimeError(
-@@ -346,11 +367,6 @@ def invoke():
-
-
- @pytest.fixture()
--def core():
-- return main
--
--
--@pytest.fixture()
- def index():
- from pip._internal.index.collector import HTMLPage, LinkCollector
-
---- a/tests/fixtures/projects/demo-failure/setup.py
-+++ b/tests/fixtures/projects/demo-failure/setup.py
-@@ -1,6 +1,6 @@
- from setuptools import setup
-
--import idna
-+import first
-
- setup(
- name="demo",
---- a/tests/fixtures/pypi.json
-+++ b/tests/fixtures/pypi.json
-@@ -22,6 +22,7 @@
- }
- },
- "urllib3": { "1.22": {}, "1.23b0": {} },
-+ "editables": { "0.2": {} },
- "chardet": { "3.0.4": {} },
- "certifi": { "2018.11.17": {} },
- "idna": { "2.7": {} },
---- a/tests/models/test_candidates.py
-+++ b/tests/models/test_candidates.py
-@@ -10,6 +10,7 @@ from pdm.models.requirements import pars
- from tests import FIXTURES
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_local_directory_metadata(project, is_editable):
- requirement_line = f"{(FIXTURES / 'projects/demo').as_posix()}"
- req = parse_requirement(requirement_line, is_editable)
-@@ -22,7 +23,7 @@ def test_parse_local_directory_metadata(
- assert candidate.version == "0.0.1"
-
-
--@pytest.mark.usefixtures("vcs")
-+@pytest.mark.usefixtures("vcs", "local_finder")
- def test_parse_vcs_metadata(project, is_editable):
- requirement_line = "git+https://github.com/test-root/demo.git@master#egg=demo"
- req = parse_requirement(requirement_line, is_editable)
-@@ -41,6 +42,7 @@ def test_parse_vcs_metadata(project, is_
- assert lockfile["revision"] == "1234567890abcdef"
-
-
-+@pytest.mark.usefixtures("local_finder")
- @pytest.mark.parametrize(
- "requirement_line",
- [
-@@ -59,6 +61,7 @@ def test_parse_artifact_metadata(require
- assert candidate.version == "0.0.1"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_metadata_with_extras(project):
- req = parse_requirement(
- f"demo[tests,security] @ file://"
-@@ -74,6 +77,7 @@ def test_parse_metadata_with_extras(proj
- ]
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_remote_link_metadata(project):
- req = parse_requirement(
- "http://fixtures.test/artifacts/demo-0.0.1-py2.py3-none-any.whl"
-@@ -88,6 +92,7 @@ def test_parse_remote_link_metadata(proj
- assert candidate.version == "0.0.1"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_extras_warning(project, recwarn):
- req = parse_requirement(
- "demo[foo] @ http://fixtures.test/artifacts/demo-0.0.1-py2.py3-none-any.whl"
-@@ -104,6 +109,7 @@ def test_extras_warning(project, recwarn
- assert candidate.version == "0.0.1"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_abnormal_specifiers(project):
- req = parse_requirement(
- "http://fixtures.test/artifacts/celery-4.4.2-py2.py3-none-any.whl"
-@@ -112,6 +118,7 @@ def test_parse_abnormal_specifiers(proje
- assert candidate.get_dependencies_from_metadata()
-
-
-+@pytest.mark.usefixtures("local_finder")
- @pytest.mark.parametrize(
- "req_str",
- [
-@@ -140,6 +147,7 @@ def test_expand_project_root_in_url(req_
- assert "${PROJECT_ROOT}" in lockfile_entry["url"]
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_project_file_on_build_error(project):
- req = parse_requirement(f"{(FIXTURES / 'projects/demo-failure').as_posix()}")
- candidate = Candidate(req, project.environment)
-@@ -151,6 +159,7 @@ def test_parse_project_file_on_build_err
- assert candidate.version == "0.0.1"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_project_file_on_build_error_with_extras(project):
- req = parse_requirement(f"{(FIXTURES / 'projects/demo-failure').as_posix()}")
- req.extras = ("security", "tests")
-@@ -162,6 +171,7 @@ def test_parse_project_file_on_build_err
- assert candidate.version == "0.0.1"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_project_file_on_build_error_no_dep(project):
- req = parse_requirement(f"{(FIXTURES / 'projects/demo-failure-no-dep').as_posix()}")
- candidate = Candidate(req, project.environment)
-@@ -170,6 +180,7 @@ def test_parse_project_file_on_build_err
- assert candidate.version == "0.0.1"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_poetry_project_metadata(project, is_editable):
- req = parse_requirement(
- f"{(FIXTURES / 'projects/poetry-demo').as_posix()}", is_editable
-@@ -181,6 +192,7 @@ def test_parse_poetry_project_metadata(p
- assert candidate.version == "0.1.0"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_parse_flit_project_metadata(project, is_editable):
- req = parse_requirement(
- f"{(FIXTURES / 'projects/flit-demo').as_posix()}", is_editable
-@@ -194,7 +206,7 @@ def test_parse_flit_project_metadata(pro
- assert candidate.version == "0.1.0"
-
-
--@pytest.mark.usefixtures("vcs")
-+@pytest.mark.usefixtures("vcs", "local_finder")
- def test_vcs_candidate_in_subdirectory(project, is_editable):
- line = (
- "git+https://github.com/test-root/demo-parent-package.git"
-@@ -218,6 +230,7 @@ def test_vcs_candidate_in_subdirectory(p
- assert candidate.version == "0.1.0"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_sdist_candidate_with_wheel_cache(project, mocker):
- file_link = Link(path_to_url((FIXTURES / "artifacts/demo-0.0.1.tar.gz").as_posix()))
- built_path = (FIXTURES / "artifacts/demo-0.0.1-py2.py3-none-any.whl").as_posix()
-@@ -240,7 +253,7 @@ def test_sdist_candidate_with_wheel_cach
- assert Path(candidate.wheel) == Path(cache_path) / Path(built_path).name
-
-
--@pytest.mark.usefixtures("vcs")
-+@pytest.mark.usefixtures("vcs", "local_finder")
- def test_cache_vcs_immutable_revision(project):
- req = parse_requirement("git+https://github.com/test-root/demo.git@master#egg=demo")
- candidate = Candidate(req, project.environment)
-@@ -264,6 +277,7 @@ def test_cache_vcs_immutable_revision(pr
- assert candidate.revision == "1234567890abcdef"
-
-
-+@pytest.mark.usefixtures("local_finder")
- def test_cache_egg_info_sdist(project):
- req = parse_requirement("demo @ http://fixtures.test/artifacts/demo-0.0.1.tar.gz")
- candidate = Candidate(req, project.environment)
---- a/tests/test_installer.py
-+++ b/tests/test_installer.py
-@@ -10,6 +10,8 @@ from pdm.models.requirements import pars
- from pdm.utils import fs_supports_symlink
- from tests import FIXTURES
-
-+pytestmark = pytest.mark.usefixtures("local_finder")
-+
-
- def test_install_wheel_with_inconsistent_dist_info(project):
- req = parse_requirement("pyfunctional")
---- a/tests/test_integration.py
-+++ b/tests/test_integration.py
-@@ -4,10 +4,11 @@ from pdm.utils import cd
-
-
- @pytest.mark.integration
-+@pytest.mark.network
- @pytest.mark.parametrize("python_version", ["2.7", "3.6", "3.7", "3.8", "3.9"])
--def test_basic_integration(python_version, project_no_init, invoke):
-+def test_basic_integration(python_version, core, tmp_path, invoke):
- """An e2e test case to ensure PDM works on all supported Python versions"""
-- project = project_no_init
-+ project = core.create_project(tmp_path)
- project.root.joinpath("foo.py").write_text("import django\n")
- additional_args = ["--no-self"] if python_version == "2.7" else []
- invoke(["init"], input="\ny\n\n\n\n\n\n>=2.7\n", obj=project, strict=True)
-@@ -25,9 +26,7 @@ def test_basic_integration(python_versio
- )
-
-
--@pytest.mark.integration
--def test_actual_list_freeze(project, invoke):
-- project.meta["requires-python"] = ">=3.6"
-- invoke(["add", "click==7.1.2"], obj=project, strict=True)
-+def test_actual_list_freeze(project, local_finder, invoke):
-+ invoke(["add", "first"], obj=project, strict=True)
- r = invoke(["list", "--freeze"], obj=project)
-- assert "click==7.1.2" in r.output
-+ assert "first==2.0.2" in r.output
---- a/tests/test_project.py
-+++ b/tests/test_project.py
-@@ -5,37 +5,36 @@ from pathlib import Path
-
- import pytest
-
--from pdm.utils import cd, temp_environ
-+from pdm.utils import cd
-
-
- def test_project_python_with_pyenv_support(project, mocker):
-
- del project.project_config["python.path"]
- project._python = None
-- with temp_environ():
-- os.environ["PDM_IGNORE_SAVED_PYTHON"] = "1"
-- mocker.patch("pdm.project.core.PYENV_INSTALLED", True)
-- mocker.patch("pdm.project.core.PYENV_ROOT", str(project.root))
-- pyenv_python = project.root / "shims/python"
-- if os.name == "nt":
-- pyenv_python = pyenv_python.with_suffix(".bat")
-- pyenv_python.parent.mkdir()
-- pyenv_python.touch()
-- mocker.patch(
-- "pythonfinder.models.python.get_python_version",
-- return_value="3.8.0",
-- )
-- mocker.patch(
-- "pdm.models.python.get_underlying_executable", return_value=sys.executable
-- )
-- assert Path(project.python.path) == pyenv_python
-- assert project.python.executable == Path(sys.executable).as_posix()
-+ os.environ["PDM_IGNORE_SAVED_PYTHON"] = "1"
-+ mocker.patch("pdm.project.core.PYENV_INSTALLED", True)
-+ mocker.patch("pdm.project.core.PYENV_ROOT", str(project.root))
-+ pyenv_python = project.root / "shims/python"
-+ if os.name == "nt":
-+ pyenv_python = pyenv_python.with_suffix(".bat")
-+ pyenv_python.parent.mkdir()
-+ pyenv_python.touch()
-+ mocker.patch(
-+ "pythonfinder.models.python.get_python_version",
-+ return_value="3.8.0",
-+ )
-+ mocker.patch(
-+ "pdm.models.python.get_underlying_executable", return_value=sys.executable
-+ )
-+ assert Path(project.python.path) == pyenv_python
-+ assert project.python.executable == Path(sys.executable).as_posix()
-
-- # Clean cache
-- project._python = None
-+ # Clean cache
-+ project._python = None
-
-- project.project_config["python.use_pyenv"] = False
-- assert Path(project.python.path) != pyenv_python
-+ project.project_config["python.use_pyenv"] = False
-+ assert Path(project.python.path) != pyenv_python
-
-
- def test_project_config_items(project):
-@@ -167,13 +166,12 @@ def test_ignore_saved_python(project):
- scripts = "Scripts" if os.name == "nt" else "bin"
- suffix = ".exe" if os.name == "nt" else ""
- venv.create(project.root / "venv")
-- with temp_environ():
-- os.environ["PDM_IGNORE_SAVED_PYTHON"] = "1"
-- assert Path(project.python.executable) != project.project_config["python.path"]
-- assert (
-- Path(project.python.executable)
-- == project.root / "venv" / scripts / f"python{suffix}"
-- )
-+ os.environ["PDM_IGNORE_SAVED_PYTHON"] = "1"
-+ assert Path(project.python.executable) != project.project_config["python.path"]
-+ assert (
-+ Path(project.python.executable)
-+ == project.root / "venv" / scripts / f"python{suffix}"
-+ )
-
-
- def test_select_dependencies(project):
diff --git a/mark-tests-path.patch b/mark-tests-path.patch
deleted file mode 100644
index dbe018c..0000000
--- a/mark-tests-path.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 23f1cf62a302633524496b0ba43239aae1e90c8e Mon Sep 17 00:00:00 2001
-From: Frost Ming
-Date: Mon, 24 Jan 2022 11:17:46 +0800
-Subject: [PATCH] Mark tests that compare paths as unstable Related to #865
-
----
- pyproject.toml | 1 +
- tests/cli/test_use.py | 5 +++--
- tests/test_project.py | 1 +
- tests/test_utils.py | 1 +
- 4 files changed, 6 insertions(+), 2 deletions(-)
-
---- a/pyproject.toml
-+++ b/pyproject.toml
-@@ -129,6 +129,7 @@ filterwarnings = [ "ignore::DeprecationW
- markers = [
- "network: Tests that require network",
- "integration: Run with all Python versions",
-+ "path: Tests that compare with the system paths",
- ]
- addopts = "-ra"
-
---- a/tests/cli/test_use.py
-+++ b/tests/cli/test_use.py
-@@ -11,8 +11,9 @@ from pdm.models.caches import JSONFileCa
-
-
- def test_use_command(project, invoke):
-- python_path = Path(shutil.which("python")).as_posix()
-- result = invoke(["use", "-f", "python"], obj=project)
-+ python = "python" if os.name == "nt" else "python3"
-+ python_path = Path(shutil.which(python)).as_posix()
-+ result = invoke(["use", "-f", python], obj=project)
- assert result.exit_code == 0
- config_content = project.root.joinpath(".pdm.toml").read_text()
- assert python_path in config_content
---- a/tests/test_project.py
-+++ b/tests/test_project.py
-@@ -206,6 +206,7 @@ def test_global_python_path_config(proje
- assert "python.path" not in p.project_config
-
-
-+@pytest.mark.path
- def test_set_non_exist_python_path(project_no_init):
- project_no_init.project_config["python.path"] = "non-exist-python"
- project_no_init._python = None
---- a/tests/test_utils.py
-+++ b/tests/test_utils.py
-@@ -50,6 +50,7 @@ def test_expend_env_vars_in_auth(given,
- assert utils.expand_env_vars_in_auth(given) == expected
-
-
-+@pytest.mark.path
- def test_find_python_in_path(tmp_path):
-
- assert (
diff --git a/pdm-1.12.6.tar.gz b/pdm-1.12.6.tar.gz
deleted file mode 100644
index 42860ba..0000000
--- a/pdm-1.12.6.tar.gz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3172844768a353edb23e7b01147d1cbbf8631c8e2e36dfbe02a8201f9ae19da5
-size 184498
diff --git a/pdm-1.15.3.tar.gz b/pdm-1.15.3.tar.gz
new file mode 100644
index 0000000..b392bea
--- /dev/null
+++ b/pdm-1.15.3.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7ba68767b626db874b7cca89476beecca397f4fddd53bdff8cf5dcd6c56e8bd3
+size 3258328
diff --git a/python-pdm.changes b/python-pdm.changes
index d3631af..c3fd01f 100644
--- a/python-pdm.changes
+++ b/python-pdm.changes
@@ -1,3 +1,58 @@
+-------------------------------------------------------------------
+Wed Jun 15 01:54:50 UTC 2022 - Steve Kowalik
+
+- Update to 1.15.2:
+ * Fix a defect in the resolution preferences that causes an infinite
+ resolution loop. #1119
+ * Update the poetry importer to support the new [tool.poetry.build] config
+ table. #1131
+ * Fix a bug where dependencies with requires-python pre-release versions
+ caused pdm update to fail with InvalidPyVersion. #1111
+ * Fix a bug that dependencies are missing from the dep graph when they are
+ depended by a requirement with extras. #1097
+ * Allow specifying lockfile other than pdm.lock by --lockfile option or
+ PDM_LOCKFILE env var. #1038
+ * Ensure the pip module inside venv in installation script. #1053
+ * Fix a bug that file paths in URLs are not correctly unquoted. #1073
+ * Fix a bug on Python 3.11 that overriding an existing command from plugins
+ raises an error. #1075
+ * Fix a bug of missing subdirectory fragment when importing from a
+ requirements.txt. #1036
+ * Fix use_cache.json with corrupted python causes pdm use error. #1039
+ * Fix a bug that requirement with extras isn't resolved to the version as
+ specified by the range. #1001
+ * Support installer 0.5.x. #1002
+ * Don't create project files in pdm search command. #993
+ * Fix a bug that the env vars in source urls in exported result are not
+ expanded. #997
+ * Don't follow symlinks for the paths in the requirement strings. #976
+ * Fix a bug that _.site_packages is overridden by default option value. #985
+ * Filter out the unmatched python versions when listing the available
+ versions. #941
+ * Fix a bug displaying the available python versions. #943
+ * Fix a bug under non-UTF8 console encoding. #960
+ * Fix a bug that data files are not copied to the destination when using
+ installation cache. #961
+ * Switch from pythonfinder to findpython as the Python version finder. #930
+ * Fix a regression issue that prereleases can't be installed if the version
+ specifier of the requirement doesn't imply that. #920
+ * Fix a race condition in parallel installation by changing metadata to a
+ lazy property. This fixes a bug that incompatible wheels are installed
+ unexpectedly. #924
+ * Fix a bug that incompatible platform-specific wheels are installed. #921
+ * Fix the compatibility issue with pip>=22.0. #875
+ * Fix the hash calculation when generating direct_url.json for a local
+ pre-built wheel. #861
+ * Reduce the number of tests that require network, and mark the rest with
+ network marker. #858
+- Remove artifacts.tar.gz, it is now included in the source tarball.
+- Drop patches because they are included upstream:
+ * mark-network-tests.patch
+ * mark-tests-path.patch
+ * sys-exec-failures.patch
+- Switch to multibuild per Python version since the testsuite takes
+ approximately seven eons.
+
-------------------------------------------------------------------
Mon Jan 24 09:37:39 UTC 2022 - Matej Cepl
diff --git a/python-pdm.spec b/python-pdm.spec
index 03b356a..79e39d6 100644
--- a/python-pdm.spec
+++ b/python-pdm.spec
@@ -1,5 +1,5 @@
#
-# spec file for package python-pdm
+# spec file
#
# Copyright (c) 2022 SUSE LLC
#
@@ -18,29 +18,38 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
-Name: python-pdm
-Version: 1.12.6
+%global flavor @BUILD_FLAVOR@%{nil}
+%if "%{flavor}" == "test-py38"
+%define psuffix -test-py38
+%define skip_python39 1
+%define skip_python310 1
+%bcond_without test
+%endif
+%if "%{flavor}" == "test-py39"
+%define psuffix -test-py39
+%define skip_python38 1
+%define skip_python310 1
+%bcond_without test
+%endif
+%if "%{flavor}" == "test-py310"
+%define psuffix -test-py310
+%define skip_python38 1
+%define skip_python39 1
+%bcond_without test
+%endif
+%if "%{flavor}" == ""
+%define psuffix %{nil}
+%bcond_with test
+%endif
+Name: python-pdm%{psuffix}
+Version: 1.15.3
Release: 0
Summary: Python Development Master
License: MIT
URL: https://github.com/pdm-project/pdm/
Source0: https://files.pythonhosted.org/packages/source/p/pdm/pdm-%{version}.tar.gz
-# Artifacts for tests from gh#pdm-project/pdm#864
-Source1: artifacts.tar.gz
-# PATCH-FIX-UPSTREAM mark-network-tests.patch gh#pdm-project/pdm#858 mcepl@suse.com
-# mark tests which require network connection (gh#pdm-project/pdm#864)
-Patch0: mark-network-tests.patch
-# PATCH-FIX-OPENSUSE sys-exec-failures.patch mcepl@suse.com
-# sys.executable is too long with python3.10
-Patch1: sys-exec-failures.patch
-# PATCH-FIX-UPSTREAM mark-tests-path.patch gh#pdm-project/pdm#865 mcepl@suse.com
-# mark tests which depend on exact paths of executables
-# https://github.com/pdm-project/pdm/commit/23f1cf62a302
-Patch2: mark-tests-path.patch
BuildRequires: %{python_module blinker}
BuildRequires: %{python_module click >= 7}
-BuildRequires: %{python_module importlib-metadata if %python-base < 3.8}
-BuildRequires: %{python_module installer}
BuildRequires: %{python_module packaging}
BuildRequires: %{python_module pdm-pep517}
BuildRequires: %{python_module pep517}
@@ -54,7 +63,6 @@ BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module shellingham >= 1.3.2}
BuildRequires: %{python_module tomli >= 1.1.0}
BuildRequires: %{python_module tomlkit}
-BuildRequires: %{python_module typing-extensions if %python-base < 3.8}
BuildRequires: %{python_module wheel >= 0.36.2}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
@@ -79,12 +87,17 @@ Requires(post): update-alternatives
Requires(postun):update-alternatives
BuildArch: noarch
# SECTION test requirements
+%if %{with test}
+BuildRequires: %{python_module findpython}
+BuildRequires: %{python_module installer}
+BuildRequires: %{python_module pdm}
BuildRequires: %{python_module pytest-cov}
BuildRequires: %{python_module pytest-mock}
BuildRequires: %{python_module pytest-xdist}
BuildRequires: %{python_module pytest}
BuildRequires: git
BuildRequires: git-lfs
+%endif
# /SECTION
%python_subpackages
@@ -94,15 +107,19 @@ installs and manages packages in a similar way to npm that
doesn't need to create a virtualenv at all!
%prep
-%autosetup -p1 -n pdm-%{version} -a1
+%autosetup -p1 -n pdm-%{version}
%build
+%if !%{with test}
%pyproject_wheel
+%endif
%install
+%if !%{with test}
%pyproject_install
%python_clone -a %{buildroot}%{_bindir}/pdm
%python_expand %fdupes %{buildroot}%{$python_sitelib}
+%endif
%post
%python_install_alternative pdm
@@ -110,14 +127,17 @@ doesn't need to create a virtualenv at all!
%postun
%python_uninstall_alternative pdm
+%if %{with test}
%check
-# the test_show_self_package is gh#pdm-project/pdm#865
-%pytest -s -k 'not (network or path or test_show_self_package or test_use_python_by_version)'
+%pytest -x -k 'not (network or path)'
+%endif
+%if !%{with test}
%files %{python_files}
%doc README.md
%license LICENSE
%python_alternative %{_bindir}/pdm
%{python_sitelib}/pdm*
+%endif
%changelog
diff --git a/sys-exec-failures.patch b/sys-exec-failures.patch
deleted file mode 100644
index 332e618..0000000
--- a/sys-exec-failures.patch
+++ /dev/null
@@ -1,14 +0,0 @@
----
- tests/test_project.py | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
-
---- a/tests/test_project.py
-+++ b/tests/test_project.py
-@@ -209,6 +209,4 @@ def test_global_python_path_config(proje
- def test_set_non_exist_python_path(project_no_init):
- project_no_init.project_config["python.path"] = "non-exist-python"
- project_no_init._python = None
-- assert os.path.normcase(project_no_init.python.executable) == os.path.normcase(
-- sys.executable
-- )
-+ assert os.path.normcase(sys.executable).startswith(os.path.normcase(project_no_init.python.executable))