Commit 4835c591 by Arun Babu Neelicattu

pep610: handle pure/plat lib differences cleanly

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