diff --git a/.gitignore b/.gitignore index 83b688b5e7..09e62b8fc3 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,7 @@ caches/ .idea/ __pypackages__ .pdm.toml +.pdm-python temp.py # Pyannotate generated stubs diff --git a/docs/docs/reference/configuration.md b/docs/docs/reference/configuration.md index 912d06bc1f..c4037ca27e 100644 --- a/docs/docs/reference/configuration.md +++ b/docs/docs/reference/configuration.md @@ -44,16 +44,15 @@ The following configuration items can be retrieved and modified by [`pdm config` | `install.cache_method` | Specify how to create links to the caches(`symlink` or `pth`) | `symlink` | Yes | | | `install.parallel` | Whether to perform installation and uninstallation in parallel | `True` | Yes | `PDM_PARALLEL_INSTALL` | | `project_max_depth` | The max depth to search for a project through the parents | 5 | No | `PDM_PROJECT_MAX_DEPTH` | -| `python.path` | The Python interpreter path | | Yes | `PDM_PYTHON` | | `python.use_pyenv` | Use the pyenv interpreter | `True` | Yes | | | `python.use_venv` | Install packages into the activated venv site packages instead of PEP 582 | `True` | Yes | `PDM_USE_VENV` | | `pypi.url` | The URL of PyPI mirror | `https://pypi.org/simple` | Yes | `PDM_PYPI_URL` | | `pypi.username` | The username to access PyPI | | Yes | `PDM_PYPI_USERNAME` | | `pypi.password` | The password to access PyPI | | Yes | `PDM_PYPI_PASSWORD` | | `pypi.ignore_stored_index` | Ignore the configured indexes | `False` | Yes | `PDM_IGNORE_STORED_INDEX` | -| `pypi.ca_certs` | Path to a PEM-encoded CA cert bundle (used for server cert verification) | The CA certificates from [certifi](https://pypi.org/project/certifi/) | Yes | | -| `pypi.client_cert` | Path to a PEM-encoded client cert and optional key | | Yes | | -| `pypi.client_key` | Path to a PEM-encoded client cert private key, if not in pypi.client_cert | | Yes | | +| `pypi.ca_certs` | Path to a PEM-encoded CA cert bundle (used for server cert verification) | The CA certificates from [certifi](https://pypi.org/project/certifi/) | No | | +| `pypi.client_cert` | Path to a PEM-encoded client cert and optional key | | No | | +| `pypi.client_key` | Path to a PEM-encoded client cert private key, if not in pypi.client_cert | | No | | | `pypi.verify_ssl` | Verify SSL certificate when query PyPI | `True` | Yes | | | `pypi.json_api` | Consult PyPI's JSON API for package metadata | `False` | Yes | `PDM_PYPI_JSON_API` | | `strategy.save` | Specify how to save versions when a package is added | `minimum`(can be: `exact`, `wildcard`, `minimum`) | Yes | | diff --git a/docs/docs/usage/config.md b/docs/docs/usage/config.md index d5d818137d..604e35dfe6 100644 --- a/docs/docs/usage/config.md +++ b/docs/docs/usage/config.md @@ -27,13 +27,13 @@ By default, the configuration are changed globally, if you want to make the conf pdm config --local pypi.url "https://test.pypi.org/simple" ``` -Any local configurations will be stored in `.pdm.toml` under the project root directory. +Any local configurations will be stored in `pdm.toml` under the project root directory. ## Configuration files The configuration files are searched in the following order: -1. `/.pdm.toml` - The project configuration +1. `/pdm.toml` - The project configuration 2. `/config.toml` - The home configuration 3. `/config.toml` - The site configuration @@ -49,7 +49,7 @@ and `` is: - `/Library/Preference/pdm` on MacOS as defined by [Apple File System Basics](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html) - `C:\ProgramData\pdm\pdm` on Windows as defined in [Known folders](https://docs.microsoft.com/en-us/windows/win32/shell/known-folders) -If `-g/--global` option is used, the first item will be replaced by `/global-project/.pdm.toml`. +If `-g/--global` option is used, the first item will be replaced by `/global-project/pdm.toml`. You can find all available configuration items in [Configuration Page](../reference/configuration.md). diff --git a/docs/docs/usage/pep582.md b/docs/docs/usage/pep582.md index 599b1a08de..1fc039e053 100644 --- a/docs/docs/usage/pep582.md +++ b/docs/docs/usage/pep582.md @@ -41,14 +41,6 @@ to the Python library search path. Now there are no built-in support or plugins for PEP 582 in most IDEs, you have to configure your tools manually. -PDM will write and store project-wide configurations in `.pdm.toml` and you are recommended to add following lines -in the `.gitignore`: - -``` -.pdm.toml -__pypackages__/ -``` - ### PyCharm Mark `__pypackages__//lib` as [Sources Root](https://www.jetbrains.com/help/pycharm/configuring-project-structure.html#mark-dir-project-view). diff --git a/docs/docs/usage/project.md b/docs/docs/usage/project.md index da52d2c616..20f5cc4f3b 100644 --- a/docs/docs/usage/project.md +++ b/docs/docs/usage/project.md @@ -12,7 +12,9 @@ You will need to answer a few questions, to help PDM to create a `pyproject.toml ## Choose a Python interpreter At first, you need to choose a Python interpreter from a list of Python versions installed on your machine. The interpreter path -will be stored in the project config `.pdm.toml` and used by subsequent commands. You can also change it later with [`pdm use`](../reference/cli.md#exec-0--use). +will be stored in `.pdm-python` and used by subsequent commands. You can also change it later with [`pdm use`](../reference/cli.md#exec-0--use). + +Alternatively, you can specify the Python interpreter path via `PDM_PYTHON` environment variable. When it is set, the path saved in `.pdm-python` will be ignored. ## Virtualenv or not @@ -92,7 +94,7 @@ Also, when you are executing [`pdm init`](../reference/cli.md#exec-0--init) or [ ## Working with version control -You **must** commit the `pyproject.toml` file. You **should** commit the `pdm.lock` file. **Do not** commit the `.pdm.toml` file. +You **must** commit the `pyproject.toml` file. You **should** commit the `pdm.lock` and `pdm.toml` file. **Do not** commit the `.pdm-python` file. The `pyproject.toml` file must be committed as it contains the project's build metadata and dependencies needed for PDM. It is also commonly used by other python tools for configuration. Read more about the `pyproject.toml` file at @@ -101,8 +103,9 @@ It is also commonly used by other python tools for configuration. Read more abou You should be committing the `pdm.lock` file, by doing so you ensure that all installers are using the same versions of dependencies. To learn how to update dependencies see [update existing dependencies](./dependency.md#update-existing-dependencies). -It is not necessary to commit your `.pdm.toml` file as it contains configuration specific to your system. -If you are using git you can safely add `.pdm.toml` to your `.gitignore` file. +`pdm.toml` contains some project-wide configuration and it may be useful to commit it for sharing. + +`.pdm-python` stores the **Python path** used by the **current** project and doesn't need to be shared. ## Show the current Python environment diff --git a/docs/docs/usage/venv.md b/docs/docs/usage/venv.md index 72c45d2245..f8b00f3d1b 100644 --- a/docs/docs/usage/venv.md +++ b/docs/docs/usage/venv.md @@ -4,7 +4,7 @@ When you run [`pdm init`](../reference/cli.md#exec-0--init) command, PDM will [a Compared to [PEP 582](https://www.python.org/dev/peps/pep-0582/), virtual environments are considered more mature and have better support in the Python ecosystem as well as IDEs. Therefore, virtualenv is the default mode if not configured otherwise. -**Virtual environments will be used if the project interpreter(the interpreter stored in `.pdm.toml`, which can be checked by `pdm info`) is from a virtualenv.** +**Virtual environments will be used if the project interpreter(the interpreter stored in `.pdm-python`, which can be checked by `pdm info`) is from a virtualenv.** ## Virtualenv auto-creation diff --git a/news/1684.feature.md b/news/1684.break.md similarity index 100% rename from news/1684.feature.md rename to news/1684.break.md diff --git a/news/1742.break.md b/news/1742.break.md new file mode 100644 index 0000000000..d6b4a20ac0 --- /dev/null +++ b/news/1742.break.md @@ -0,0 +1 @@ +Move the project python path to its own file, and rename the project config file as `pdm.toml` which can be committed to the VCS. diff --git a/src/pdm/cli/actions.py b/src/pdm/cli/actions.py index 433c095ec7..0377dc85fe 100644 --- a/src/pdm/cli/actions.py +++ b/src/pdm/cli/actions.py @@ -614,7 +614,8 @@ def version_matcher(py_version: PythonInfo) -> bool: if not save: return selected_python - old_python = PythonInfo.from_path(project.config["python.path"]) if "python.path" in project.config else None + saved_python = project._saved_python + old_python = PythonInfo.from_path(saved_python) if saved_python else None project.core.ui.echo( f"Using Python interpreter: [success]{str(selected_python.path)}[/] ({selected_python.identifier})" ) diff --git a/src/pdm/cli/commands/venv/activate.py b/src/pdm/cli/commands/venv/activate.py index 7c0395c88a..2a68c9e33b 100644 --- a/src/pdm/cli/commands/venv/activate.py +++ b/src/pdm/cli/commands/venv/activate.py @@ -30,8 +30,8 @@ def handle(self, project: Project, options: argparse.Namespace) -> None: ) raise SystemExit(1) else: - # Use what is saved in .pdm.toml - interpreter = project.project_config.get("python.path") + # Use what is saved in .pdm-python + interpreter = project._saved_python if not interpreter: project.core.ui.echo( "The project doesn't have a saved python.path. Run [success]pdm use[/] to pick one.", diff --git a/src/pdm/cli/commands/venv/backends.py b/src/pdm/cli/commands/venv/backends.py index 829e9bc5dc..da2983e8f9 100644 --- a/src/pdm/cli/commands/venv/backends.py +++ b/src/pdm/cli/commands/venv/backends.py @@ -33,7 +33,7 @@ def pip_args(self, with_pip: bool) -> Iterable[str]: @cached_property def _resolved_interpreter(self) -> PythonInfo: if not self.python: - saved_python = self.project.project_config.get("python.path") + saved_python = self.project._saved_python if saved_python: return PythonInfo.from_path(saved_python) for py_version in self.project.find_interpreters(self.python): diff --git a/src/pdm/cli/commands/venv/list.py b/src/pdm/cli/commands/venv/list.py index 37b3e3a764..524a109d72 100644 --- a/src/pdm/cli/commands/venv/list.py +++ b/src/pdm/cli/commands/venv/list.py @@ -15,7 +15,7 @@ class ListCommand(BaseCommand): def handle(self, project: Project, options: argparse.Namespace) -> None: project.core.ui.echo("Virtualenvs created with this project:\n") for ident, venv in iter_venvs(project): - saved_python = project.project_config.get("python.path") + saved_python = project._saved_python if saved_python and Path(saved_python).parent.parent == venv: mark = "*" else: diff --git a/src/pdm/cli/commands/venv/remove.py b/src/pdm/cli/commands/venv/remove.py index 76ae66dde1..4796c26569 100644 --- a/src/pdm/cli/commands/venv/remove.py +++ b/src/pdm/cli/commands/venv/remove.py @@ -2,11 +2,11 @@ import shutil from pathlib import Path -from pdm.project import Project from pdm import termui from pdm.cli.commands.base import BaseCommand from pdm.cli.commands.venv.utils import iter_venvs from pdm.cli.options import verbose_option +from pdm.project import Project class RemoveCommand(BaseCommand): @@ -29,11 +29,9 @@ def handle(self, project: Project, options: argparse.Namespace) -> None: if ident == options.env: if options.yes or termui.confirm(f"[warning]Will remove: [success]{venv}[/], continue?", default=True): shutil.rmtree(venv) - if ( - project.project_config.get("python.path") - and Path(project.project_config["python.path"]).parent.parent == venv - ): - del project.project_config["python.path"] + saved_python = project._saved_python + if saved_python and Path(saved_python).parent.parent == venv: + project._saved_python = None project.core.ui.echo("Removed successfully!") break else: diff --git a/src/pdm/cli/completions/pdm.fish b/src/pdm/cli/completions/pdm.fish index d9aa4de1d9..a96ebc74ed 100644 --- a/src/pdm/cli/completions/pdm.fish +++ b/src/pdm/cli/completions/pdm.fish @@ -13,7 +13,7 @@ end # global options complete -c pdm -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -l config -d 'Specify another config file path(env var: PDM_CONFIG_FILE)' complete -c pdm -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -l help -d 'show this help message and exit' -complete -c pdm -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -l ignore-python -d 'Ignore the Python path saved in the .pdm.toml config' +complete -c pdm -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -l ignore-python -d 'Ignore the Python path saved in .pdm-python' complete -c pdm -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -l pep582 -d 'Print the command line to be eval\'d by the shell' complete -c pdm -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -l verbose -d '-v for detailed output and -vv for more detailed' complete -c pdm -n '__fish_pdm_a919b69078acdf0a_complete_no_subcommand' -l version -d 'Show version' diff --git a/src/pdm/cli/completions/pdm.zsh b/src/pdm/cli/completions/pdm.zsh index e2ab8c56a5..e689877099 100644 --- a/src/pdm/cli/completions/pdm.zsh +++ b/src/pdm/cli/completions/pdm.zsh @@ -43,7 +43,7 @@ _pdm() { $arguments \ {-c,--config}'[Specify another config file path(env var: PDM_CONFIG_FILE)]' \ {-V,--version}'[Show the version and exit]' \ - {-I,--ignore-python}'[Ignore the Python path saved in the .pdm.toml config]' \ + {-I,--ignore-python}'[Ignore the Python path saved in .pdm-python]' \ '--pep582:Print the command line to be eval by the shell:shell:(zsh bash fish tcsh csh)' \ '*:: :->_subcmds' \ && return 0 diff --git a/src/pdm/cli/options.py b/src/pdm/cli/options.py index b7a55ba4a2..a40a6363f0 100644 --- a/src/pdm/cli/options.py +++ b/src/pdm/cli/options.py @@ -325,7 +325,7 @@ def no_isolation_callback( "-I", "--ignore-python", action="store_true", - help="Ignore the Python path saved in the .pdm.toml config", + help="Ignore the Python path saved in .pdm-python", ) prerelease_option = Option( diff --git a/src/pdm/project/config.py b/src/pdm/project/config.py index 88ed8ba5c2..9d2af7c087 100644 --- a/src/pdm/project/config.py +++ b/src/pdm/project/config.py @@ -26,7 +26,7 @@ def load_config(file_path: Path) -> dict[str, Any]: """Load a nested TOML document into key-value pairs - E.g. ["python"]["path"] will be loaded as "python.path" key. + E.g. ["python"]["use_venv"] will be loaded as "python.use_venv" key. """ def get_item(sub_data: Mapping[str, Any]) -> dict[str, Any]: @@ -153,7 +153,6 @@ class Config(MutableMapping[str, str]): "`symlink` or `pth` to create links to the cached installation", "symlink", ), - "python.path": ConfigItem("The Python interpreter path", env_var="PDM_PYTHON"), "python.use_pyenv": ConfigItem("Use the pyenv interpreter", True, coerce=ensure_boolean), "python.use_venv": ConfigItem( "Install packages into the activated venv site packages instead of PEP 582", @@ -170,7 +169,7 @@ class Config(MutableMapping[str, str]): "pypi.username": ConfigItem("The username to access PyPI", env_var="PDM_PYPI_USERNAME"), "pypi.password": ConfigItem("The password to access PyPI", env_var="PDM_PYPI_PASSWORD"), "pypi.ca_certs": ConfigItem( - "Path to a CA certificate bundle used for verifying the identity of the PyPI server", + "Path to a CA certificate bundle used for verifying the identity of the PyPI server", global_only=True ), "pypi.ignore_stored_index": ConfigItem( "Ignore the configured indexes", @@ -178,12 +177,8 @@ class Config(MutableMapping[str, str]): env_var="PDM_IGNORE_STORED_INDEX", coerce=ensure_boolean, ), - "pypi.client_cert": ConfigItem( - "Path to client certificate file, or combined cert/key file", - ), - "pypi.client_key": ConfigItem( - "Path to client cert keyfile, if not in pypi.client_cert", - ), + "pypi.client_cert": ConfigItem("Path to client certificate file, or combined cert/key file", global_only=True), + "pypi.client_key": ConfigItem("Path to client cert keyfile, if not in pypi.client_cert", global_only=True), "pypi.json_api": ConfigItem( "Consult PyPI's JSON API for package metadata", False, diff --git a/src/pdm/project/core.py b/src/pdm/project/core.py index 14e6311277..eaacedcdec 100644 --- a/src/pdm/project/core.py +++ b/src/pdm/project/core.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import hashlib import os import re @@ -132,7 +133,7 @@ def scripts(self) -> dict[str, str | dict[str, str]]: @cached_property def project_config(self) -> Config: """Read-and-writable configuration dict for project settings""" - return Config(self.root / ".pdm.toml") + return Config(self.root / "pdm.toml") @property def name(self) -> str | None: @@ -152,7 +153,24 @@ def python(self) -> PythonInfo: @python.setter def python(self, value: PythonInfo) -> None: self._python = value - self.project_config["python.path"] = value.path + self._saved_python = value.path.as_posix() + + @property + def _saved_python(self) -> str | None: + if os.getenv("PDM_PYTHON"): + return os.getenv("PDM_PYTHON") + with contextlib.suppress(FileNotFoundError): + return self.root.joinpath(".pdm-python").read_text("utf-8").strip() + return None + + @_saved_python.setter + def _saved_python(self, value: str | None) -> None: + python_file = self.root.joinpath(".pdm-python") + if value is None: + with contextlib.suppress(FileNotFoundError): + python_file.unlink() + return + python_file.write_text(value, "utf-8") def resolve_interpreter(self) -> PythonInfo: """Get the Python interpreter path.""" @@ -166,12 +184,12 @@ def note(message: str) -> None: self.core.ui.echo(message, style="warning", err=True) config = self.config - if config.get("python.path") and not os.getenv("PDM_IGNORE_SAVED_PYTHON"): - saved_path = config["python.path"] + saved_path = self._saved_python + if saved_path and not os.getenv("PDM_IGNORE_SAVED_PYTHON"): python = PythonInfo.from_path(saved_path) if match_version(python): return python - self.project_config.pop("python.path", None) + self._saved_python = None # Clear the saved path if it doesn't match if config.get("python.use_venv") and not self.is_global: # Resolve virtual environments from env-vars @@ -635,7 +653,7 @@ def _get_python_finder(self) -> Finder: finder = Finder(resolve_symlinks=True) if self.config["python.use_venv"]: - finder._providers.insert(0, VenvProvider(self)) + finder.add_provider(VenvProvider(self), 0) return finder # compatibility, shouldn't be used directly diff --git a/src/pdm/pytest.py b/src/pdm/pytest.py index 49f5c1ad39..284422662b 100644 --- a/src/pdm/pytest.py +++ b/src/pdm/pytest.py @@ -395,7 +395,7 @@ def project_no_init( python_path = find_python_in_path(sys.base_prefix) if python_path is None: raise ValueError("Unable to find a Python path") - p.project_config["python.path"] = python_path.as_posix() + p._saved_python = python_path.as_posix() monkeypatch.delenv("VIRTUAL_ENV", raising=False) monkeypatch.delenv("CONDA_PREFIX", raising=False) monkeypatch.delenv("PEP582_PACKAGES", raising=False) diff --git a/tests/cli/test_config.py b/tests/cli/test_config.py index d496a10d7c..f3f35d22ff 100644 --- a/tests/cli/test_config.py +++ b/tests/cli/test_config.py @@ -66,11 +66,11 @@ def test_config_env_var_shadowing(project, invoke, monkeypatch): def test_config_project_global_precedence(project, invoke): - invoke(["config", "python.path", "/path/to/foo"], obj=project) - invoke(["config", "-l", "python.path", "/path/to/bar"], obj=project) + invoke(["config", "python.use_pyenv", "true"], obj=project) + invoke(["config", "-l", "python.use_pyenv", "false"], obj=project) - result = invoke(["config", "python.path"], obj=project) - assert result.output.strip() == "/path/to/bar" + result = invoke(["config", "python.use_pyenv"], obj=project) + assert result.output.strip() == "False" def test_specify_config_file(tmp_path, invoke, monkeypatch): diff --git a/tests/cli/test_others.py b/tests/cli/test_others.py index efdd771e7d..6fc830fbea 100644 --- a/tests/cli/test_others.py +++ b/tests/cli/test_others.py @@ -94,7 +94,7 @@ def test_search_package(invoke, tmp_path): assert result.exit_code == 0 assert len(result.output.splitlines()) > 0 assert not tmp_path.joinpath("__pypackages__").exists() - assert not tmp_path.joinpath(".pdm.toml").exists() + assert not tmp_path.joinpath(".pdm-python").exists() @pytest.mark.network diff --git a/tests/cli/test_use.py b/tests/cli/test_use.py index e65cac76ad..6b28db838f 100644 --- a/tests/cli/test_use.py +++ b/tests/cli/test_use.py @@ -15,8 +15,8 @@ def test_use_command(project, invoke): python_path = shutil.which(python) result = invoke(["use", "-f", python], obj=project) assert result.exit_code == 0 - config_content = project.root.joinpath(".pdm.toml").read_text() - assert python_path.replace("\\", "\\\\") in config_content + config_content = project.root.joinpath(".pdm-python").read_text() + assert Path(python_path).as_posix() in config_content result = invoke(["use", "-f", python_path], obj=project) assert result.exit_code == 0 diff --git a/tests/cli/test_venv.py b/tests/cli/test_venv.py index 0ef93a134d..65d6213ebe 100644 --- a/tests/cli/test_venv.py +++ b/tests/cli/test_venv.py @@ -30,13 +30,13 @@ def fake_create(self, location, *args): @pytest.mark.usefixtures("fake_create") def test_venv_create(invoke, project): - project.project_config.pop("python.path", None) + project._saved_python = None project.project_config["venv.in_project"] = False result = invoke(["venv", "create"], obj=project) assert result.exit_code == 0, result.stderr venv_path = re.match(r"Virtualenv (.+) is created successfully", result.output).group(1) assert os.path.exists(venv_path) - assert "python.path" not in project.project_config + assert not project._saved_python @pytest.mark.usefixtures("fake_create") @@ -135,7 +135,7 @@ def test_venv_activate_custom_prompt(invoke, mocker, project): def test_venv_activate_project_without_python(invoke, project): - project.project_config.pop("python.path", None) + project._saved_python = None result = invoke(["venv", "activate"], obj=project) assert result.exit_code != 0 assert "The project doesn't have a saved python.path" in result.stderr @@ -150,9 +150,8 @@ def test_venv_activate_error(invoke, project): assert result.exit_code != 0 assert "No virtualenv with key" in result.stderr - project.project_config["python.path"] = os.path.abspath("fake/bin/python") + project._saved_python = os.path.abspath("fake/bin/python") result = invoke(["venv", "activate"], obj=project) - print(project.project_config.get("python.path")) assert result.exit_code != 0, result.output + result.stderr assert "Can't activate a non-venv Python" in result.stderr @@ -161,7 +160,7 @@ def test_venv_activate_error(invoke, project): @pytest.mark.parametrize("keep_pypackages", [True, False]) def test_venv_auto_create(invoke, mocker, project, keep_pypackages): creator = mocker.patch("pdm.cli.commands.venv.backends.Backend.create") - del project.project_config["python.path"] + project._saved_python = None if keep_pypackages: project.root.joinpath("__pypackages__").mkdir(exist_ok=True) else: diff --git a/tests/test_project.py b/tests/test_project.py index 9fec641b5e..5ed22619f8 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -12,7 +12,7 @@ def test_project_python_with_pyenv_support(project, mocker, monkeypatch): - del project.project_config["python.path"] + project._saved_python = None project._python = None monkeypatch.setenv("PDM_IGNORE_SAVED_PYTHON", "1") mocker.patch("pdm.project.core.PYENV_ROOT", str(project.root)) @@ -106,7 +106,7 @@ def test_auto_global_project(tmp_path, core): def test_project_use_venv(project): - del project.project_config["python.path"] + project._saved_python = None project._python = None scripts = "Scripts" if os.name == "nt" else "bin" suffix = ".exe" if os.name == "nt" else "" @@ -135,7 +135,7 @@ def test_project_auto_detect_venv(project): project.project_config["python.use_venv"] = True project._python = None - project.project_config["python.path"] = (project.root / "test_venv" / scripts / f"python{suffix}").as_posix() + project._saved_python = (project.root / "test_venv" / scripts / f"python{suffix}").as_posix() assert project.environment.is_global @@ -148,7 +148,7 @@ def test_ignore_saved_python(project, monkeypatch): suffix = ".exe" if os.name == "nt" else "" venv.create(project.root / "venv") monkeypatch.setenv("PDM_IGNORE_SAVED_PYTHON", "1") - assert project.python.executable != project.project_config["python.path"] + assert project.python.executable != project._saved_python assert project.python.executable == project.root / "venv" / scripts / f"python{suffix}" @@ -178,18 +178,9 @@ def test_select_dependencies(project): ] -def test_global_python_path_config(project_no_init, tmp_path): - tmp_path.joinpath(".pdm.toml").unlink() - project_no_init.global_config["python.path"] = sys.executable - # Recreate the project to clean cached properties - p = project_no_init.core.create_project(project_no_init.root, global_config=tmp_path / ".pdm-home/config.toml") - assert p.python.executable == Path(sys.executable) - 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._saved_python = "non-exist-python" project_no_init._python = None assert project_no_init.python.executable.name != "non-exist-python" @@ -197,21 +188,21 @@ def test_set_non_exist_python_path(project_no_init): @pytest.mark.usefixtures("venv_backends") def test_create_venv_first_time(invoke, project, local_finder): project.project_config.update({"venv.in_project": False}) - del project.project_config["python.path"] + project._saved_python = None result = invoke(["install"], obj=project) assert result.exit_code == 0 venv_parent = project.root / "venvs" venv_path = next(venv_parent.iterdir(), None) assert venv_path is not None - assert Path(project.project_config["python.path"]).relative_to(venv_path) + assert Path(project._saved_python).relative_to(venv_path) @pytest.mark.usefixtures("venv_backends", "local_finder") @pytest.mark.parametrize("with_pip", [True, False]) def test_create_venv_in_project(invoke, project, with_pip): project.project_config.update({"venv.in_project": True, "venv.with_pip": with_pip}) - del project.project_config["python.path"] + project._saved_python = None result = invoke(["install"], obj=project) assert result.exit_code == 0 assert project.root.joinpath(".venv").exists() @@ -222,7 +213,7 @@ def test_create_venv_in_project(invoke, project, with_pip): @pytest.mark.usefixtures("venv_backends") def test_find_interpreters_from_venv(invoke, project, local_finder): project.project_config.update({"venv.in_project": False}) - del project.project_config["python.path"] + project._saved_python = None result = invoke(["install"], obj=project) assert result.exit_code == 0 venv_parent = project.root / "venvs" @@ -234,7 +225,7 @@ def test_find_interpreters_from_venv(invoke, project, local_finder): @pytest.mark.usefixtures("local_finder") def test_find_interpreters_without_duplicate_relative_paths(invoke, project): - del project.project_config["python.path"] + project._saved_python = None venv.create(project.root / ".venv", clear=True) with cd(project.root): bin_dir = "Scripts" if os.name == "nt" else "bin"