Commit 4835c591 by Arun Babu Neelicattu

pep610: handle pure/plat lib differences cleanly

parent a12d1428
......@@ -714,6 +714,19 @@ class Executor:
def _should_write_operation(self, operation: Operation) -> bool:
return not operation.skipped or self._dry_run or self._verbose
@staticmethod
def _package_dist_info_path(package: "Package") -> Path:
from poetry.core.masonry.utils.helpers import escape_name
from poetry.core.masonry.utils.helpers import escape_version
return Path(
f"{escape_name(package.pretty_name)}-{escape_version(package.version.text)}.dist-info"
)
@classmethod
def _direct_url_json_path(cls, package: "Package") -> Path:
return cls._package_dist_info_path(package) / "direct_url.json"
def _save_url_reference(self, operation: "OperationTypes") -> None:
"""
Create and store a PEP-610 `direct_url.json` file, if needed.
......@@ -721,9 +734,6 @@ class Executor:
if operation.job_type not in {"install", "update"}:
return
from poetry.core.masonry.utils.helpers import escape_name
from poetry.core.masonry.utils.helpers import escape_version
package = operation.package
if not package.source_url:
......@@ -732,14 +742,10 @@ class Executor:
# distribution.
# That's not what we want so we remove the direct_url.json file,
# if it exists.
dist_info = self._env.site_packages.path.joinpath(
"{}-{}.dist-info".format(
escape_name(package.pretty_name),
escape_version(package.version.text),
)
)
if dist_info.exists() and dist_info.joinpath("direct_url.json").exists():
dist_info.joinpath("direct_url.json").unlink()
for direct_url in self._env.site_packages.find(
self._direct_url_json_path(package), True
):
direct_url.unlink()
return
......@@ -755,16 +761,15 @@ class Executor:
url_reference = self._create_file_url_reference(package)
if url_reference:
dist_info = self._env.site_packages.path.joinpath(
"{}-{}.dist-info".format(
escape_name(package.name), escape_version(package.version.text)
)
)
if dist_info.exists():
dist_info.joinpath("direct_url.json").write_text(
json.dumps(url_reference), encoding="utf-8"
for path in self._env.site_packages.find(
self._package_dist_info_path(package), writable_only=True
):
self._env.site_packages.write_text(
path / "direct_url.json",
json.dumps(url_reference),
encoding="utf-8",
)
break
def _create_git_url_reference(
self, package: "Package"
......
......@@ -117,10 +117,7 @@ class PipInstaller(BaseInstaller):
raise
# This is a workaround for https://github.com/pypa/pip/issues/4176
nspkg_pth_file = self._env.site_packages.path / "{}-nspkg.pth".format(
package.name
)
if nspkg_pth_file.exists():
for nspkg_pth_file in self._env.site_packages.find(f"{package.name}-nspkg.pth"):
nspkg_pth_file.unlink()
# If we have a VCS package, remove its source directory
......
......@@ -152,17 +152,34 @@ print(json.dumps(sysconfig.get_paths()))
class SitePackages:
def __init__(
self, path: Path, fallbacks: List[Path] = None, skip_write_checks: bool = False
self,
purelib: Path,
platlib: Optional[Path] = None,
fallbacks: List[Path] = None,
skip_write_checks: bool = False,
) -> None:
self._path = path
self._purelib = purelib
self._platlib = platlib or purelib
if platlib and platlib.resolve() == purelib.resolve():
self._platlib = purelib
self._fallbacks = fallbacks or []
self._skip_write_checks = skip_write_checks
self._candidates = [self._path] + self._fallbacks
self._candidates = list({self._purelib, self._platlib}) + self._fallbacks
self._writable_candidates = None if not skip_write_checks else self._candidates
@property
def path(self) -> Path:
return self._path
return self._purelib
@property
def purelib(self) -> Path:
return self._purelib
@property
def platlib(self) -> Path:
return self._platlib
@property
def candidates(self) -> List[Path]:
......@@ -200,12 +217,16 @@ class SitePackages:
return [candidate / path for candidate in candidates if candidate]
def _path_method_wrapper(
self, path: Path, method: str, *args: Any, **kwargs: Any
self,
path: Union[str, Path],
method: str,
*args: Any,
return_first: bool = True,
writable_only: bool = False,
**kwargs: Any,
) -> Union[Tuple[Path, Any], List[Tuple[Path, Any]]]:
# TODO: Move to parameters after dropping Python 2.7
return_first = kwargs.pop("return_first", True)
writable_only = kwargs.pop("writable_only", False)
if isinstance(path, str):
path = Path(path)
candidates = self.make_candidates(path, writable_only=writable_only)
......@@ -234,19 +255,19 @@ class SitePackages:
raise OSError("Unable to access any of {}".format(paths_csv(candidates)))
def write_text(self, path: Path, *args: Any, **kwargs: Any) -> Path:
def write_text(self, path: Union[str, Path], *args: Any, **kwargs: Any) -> Path:
return self._path_method_wrapper(path, "write_text", *args, **kwargs)[0]
def mkdir(self, path: Path, *args: Any, **kwargs: Any) -> Path:
def mkdir(self, path: Union[str, Path], *args: Any, **kwargs: Any) -> Path:
return self._path_method_wrapper(path, "mkdir", *args, **kwargs)[0]
def exists(self, path: Path) -> bool:
def exists(self, path: Union[str, Path]) -> bool:
return any(
value[-1]
for value in self._path_method_wrapper(path, "exists", return_first=False)
)
def find(self, path: Path, writable_only: bool = False) -> List[Path]:
def find(self, path: Union[str, Path], writable_only: bool = False) -> List[Path]:
return [
value[0]
for value in self._path_method_wrapper(
......@@ -990,7 +1011,10 @@ class Env:
# we disable write checks if no user site exist
fallbacks = [self.usersite] if self.usersite else []
self._site_packages = SitePackages(
self.purelib, fallbacks, skip_write_checks=False if fallbacks else True
self.purelib,
self.platlib,
fallbacks,
skip_write_checks=False if fallbacks else True,
)
return self._site_packages
......
......@@ -280,9 +280,10 @@ def test_executor_should_write_pep610_url_references_for_files(
executor = Executor(tmp_venv, pool, config, io)
executor.execute([Install(package)])
dist_info = tmp_venv.site_packages.path.joinpath("demo-0.1.0.dist-info")
assert dist_info.exists()
dist_info = "demo-0.1.0.dist-info"
assert tmp_venv.site_packages.exists(dist_info)
dist_info = tmp_venv.site_packages.find(dist_info)[0]
direct_url_file = dist_info.joinpath("direct_url.json")
assert direct_url_file.exists()
......@@ -303,9 +304,10 @@ def test_executor_should_write_pep610_url_references_for_directories(
executor = Executor(tmp_venv, pool, config, io)
executor.execute([Install(package)])
dist_info = tmp_venv.site_packages.path.joinpath("simple_project-1.2.3.dist-info")
assert dist_info.exists()
dist_info = "simple_project-1.2.3.dist-info"
assert tmp_venv.site_packages.exists(dist_info)
dist_info = tmp_venv.site_packages.find(dist_info)[0]
direct_url_file = dist_info.joinpath("direct_url.json")
assert direct_url_file.exists()
......@@ -330,9 +332,10 @@ def test_executor_should_write_pep610_url_references_for_editable_directories(
executor = Executor(tmp_venv, pool, config, io)
executor.execute([Install(package)])
dist_info = tmp_venv.site_packages.path.joinpath("simple_project-1.2.3.dist-info")
assert dist_info.exists()
dist_info_dir = "simple_project-1.2.3.dist-info"
assert tmp_venv.site_packages.exists(dist_info_dir)
dist_info = tmp_venv.site_packages.find(dist_info_dir)[0]
direct_url_file = dist_info.joinpath("direct_url.json")
assert direct_url_file.exists()
......@@ -355,9 +358,10 @@ def test_executor_should_write_pep610_url_references_for_urls(
executor = Executor(tmp_venv, pool, config, io)
executor.execute([Install(package)])
dist_info = tmp_venv.site_packages.path.joinpath("demo-0.1.0.dist-info")
assert dist_info.exists()
dist_info = "demo-0.1.0.dist-info"
assert tmp_venv.site_packages.exists(dist_info)
dist_info = tmp_venv.site_packages.find(dist_info)[0]
direct_url_file = dist_info.joinpath("direct_url.json")
assert direct_url_file.exists()
......@@ -385,9 +389,10 @@ def test_executor_should_write_pep610_url_references_for_git(
executor = Executor(tmp_venv, pool, config, io)
executor.execute([Install(package)])
dist_info = tmp_venv.site_packages.path.joinpath("demo-0.1.2.dist-info")
assert dist_info.exists()
dist_info = "demo-0.1.2.dist-info"
assert tmp_venv.site_packages.exists(dist_info)
dist_info = tmp_venv.site_packages.find(dist_info)[0]
direct_url_file = dist_info.joinpath("direct_url.json")
assert direct_url_file.exists()
......
import re
import shutil
from pathlib import Path
......@@ -190,11 +191,6 @@ def test_uninstall_git_package_nspkg_pth_cleanup(mocker, tmp_venv, pool):
source_reference="master",
)
# we do this here because the virtual env might not be usable if failure case is triggered
pth_file_candidate = tmp_venv.site_packages.path / "{}-nspkg.pth".format(
package.name
)
# in order to reproduce the scenario where the git source is removed prior to proper
# clean up of nspkg.pth file, we need to make sure the fixture is copied and not
# symlinked into the git src directory
......@@ -213,8 +209,9 @@ def test_uninstall_git_package_nspkg_pth_cleanup(mocker, tmp_venv, pool):
installer.install(package)
installer.remove(package)
assert not Path(pth_file_candidate).exists()
pth_file = f"{package.name}-nspkg.pth"
assert not tmp_venv.site_packages.exists(pth_file)
# any command in the virtual environment should trigger the error message
output = tmp_venv.run("python", "-m", "site")
assert "Error processing line 1 of {}".format(pth_file_candidate) not in output
assert not re.match(rf"Error processing line 1 of .*{pth_file}", output)
......@@ -78,16 +78,18 @@ def test_builder_installs_proper_files_for_standard_packages(simple_poetry, tmp_
builder.build()
assert tmp_venv._bin_dir.joinpath("foo").exists()
assert tmp_venv.site_packages.path.joinpath("simple_project.pth").exists()
pth_file = "simple_project.pth"
assert tmp_venv.site_packages.exists(pth_file)
assert (
simple_poetry.file.parent.resolve().as_posix()
== tmp_venv.site_packages.path.joinpath("simple_project.pth")
.read_text()
.strip(os.linesep)
== tmp_venv.site_packages.find(pth_file)[0].read_text().strip(os.linesep)
)
dist_info = tmp_venv.site_packages.path.joinpath("simple_project-1.2.3.dist-info")
assert dist_info.exists()
dist_info = "simple_project-1.2.3.dist-info"
assert tmp_venv.site_packages.exists(dist_info)
dist_info = tmp_venv.site_packages.find(dist_info)[0]
assert dist_info.joinpath("INSTALLER").exists()
assert dist_info.joinpath("METADATA").exists()
assert dist_info.joinpath("RECORD").exists()
......@@ -134,7 +136,9 @@ My Package
assert metadata == dist_info.joinpath("METADATA").read_text(encoding="utf-8")
records = dist_info.joinpath("RECORD").read_text()
assert str(tmp_venv.site_packages.path.joinpath("simple_project.pth")) in records
pth_file = "simple_project.pth"
assert tmp_venv.site_packages.exists(pth_file)
assert str(tmp_venv.site_packages.find(pth_file)[0]) in records
assert str(tmp_venv._bin_dir.joinpath("foo")) in records
assert str(tmp_venv._bin_dir.joinpath("baz")) in records
assert str(dist_info.joinpath("METADATA")) in records
......@@ -201,8 +205,10 @@ def test_builder_installs_proper_files_when_packages_configured(
builder = EditableBuilder(project_with_include, tmp_venv, NullIO())
builder.build()
pth_file = tmp_venv.site_packages.path.joinpath("with_include.pth")
assert pth_file.is_file()
pth_file = "with_include.pth"
assert tmp_venv.site_packages.exists(pth_file)
pth_file = tmp_venv.site_packages.find(pth_file)[0]
paths = set()
with pth_file.open() as f:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment