Commit cee833ac by Petter Strandmark Committed by Arun Babu Neelicattu

installed repository: handle executable .pth files

Resolves: #2597
parent 687a897e
from typing import Set
from poetry.core.packages import Package from poetry.core.packages import Package
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils._compat import metadata from poetry.utils._compat import metadata
...@@ -11,6 +13,37 @@ _VENDORS = Path(__file__).parent.parent.joinpath("_vendor") ...@@ -11,6 +13,37 @@ _VENDORS = Path(__file__).parent.parent.joinpath("_vendor")
class InstalledRepository(Repository): class InstalledRepository(Repository):
@classmethod @classmethod
def get_package_paths(cls, sitedir, name): # type: (Path, str) -> Set[Path]
"""
Process a .pth file within the site-packages directory, and return any valid
paths. We skip executable .pth files as there is no reliable means to do this
without side-effects to current run-time. Mo check is made that the item refers
to a directory rather than a file, however, in order to maintain backwards
compatibility, we allow non-existing paths to be discovered. The latter
behaviour is different to how Python's site-specific hook configuration works.
Reference: https://docs.python.org/3.8/library/site.html
:param sitedir: The site-packages directory to search for .pth file.
:param name: The name of the package to search .pth file for.
:return: A `Set` of valid `Path` objects.
"""
paths = set()
pth_file = sitedir.joinpath("{}.pth".format(name))
if pth_file.exists():
with pth_file.open() as f:
for line in f:
line = line.strip()
if line and not line.startswith(("#", "import ", "import\t")):
path = Path(line)
if not path.is_absolute():
path = sitedir.joinpath(path)
paths.add(path)
return paths
@classmethod
def load(cls, env): # type: (Env) -> InstalledRepository def load(cls, env): # type: (Env) -> InstalledRepository
""" """
Load installed packages. Load installed packages.
...@@ -49,19 +82,14 @@ class InstalledRepository(Repository): ...@@ -49,19 +82,14 @@ class InstalledRepository(Repository):
is_standard_package = False is_standard_package = False
if is_standard_package: if is_standard_package:
if ( if path.name.endswith(".dist-info"):
path.name.endswith(".dist-info") paths = cls.get_package_paths(
and env.site_packages.joinpath( sitedir=env.site_packages, name=package.pretty_name
"{}.pth".format(package.pretty_name) )
).exists() if paths:
): # TODO: handle multiple source directories?
with env.site_packages.joinpath(
"{}.pth".format(package.pretty_name)
).open() as f:
directory = Path(f.readline().strip())
package.source_type = "directory" package.source_type = "directory"
package.source_url = directory.as_posix() package.source_url = paths.pop().as_posix()
continue continue
src_path = env.path / "src" src_path = env.path / "src"
......
Metadata-Version: 2.1
Name: editable-with-import
Version: 2.3.4
Summary: Editable description.
License: MIT
Keywords: cli,commands
Author: Foo Bar
Author-email: foo@bar.com
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Description-Content-Type: text/x-rst
Editable
####
...@@ -18,6 +18,7 @@ INSTALLED_RESULTS = [ ...@@ -18,6 +18,7 @@ INSTALLED_RESULTS = [
), ),
metadata.PathDistribution(VENDOR_DIR / "attrs-19.3.0.dist-info"), metadata.PathDistribution(VENDOR_DIR / "attrs-19.3.0.dist-info"),
metadata.PathDistribution(SITE_PACKAGES / "editable-2.3.4.dist-info"), metadata.PathDistribution(SITE_PACKAGES / "editable-2.3.4.dist-info"),
metadata.PathDistribution(SITE_PACKAGES / "editable-with-import-2.3.4.dist-info"),
] ]
...@@ -46,7 +47,7 @@ def test_load(mocker): ...@@ -46,7 +47,7 @@ def test_load(mocker):
mocker.patch("poetry.repositories.installed_repository._VENDORS", str(VENDOR_DIR)) mocker.patch("poetry.repositories.installed_repository._VENDORS", str(VENDOR_DIR))
repository = InstalledRepository.load(MockEnv(path=ENV_DIR)) repository = InstalledRepository.load(MockEnv(path=ENV_DIR))
assert len(repository.packages) == 4 assert len(repository.packages) == 5
cleo = repository.packages[0] cleo = repository.packages[0]
assert cleo.name == "cleo" assert cleo.name == "cleo"
...@@ -56,11 +57,11 @@ def test_load(mocker): ...@@ -56,11 +57,11 @@ def test_load(mocker):
== "Cleo allows you to create beautiful and testable command-line interfaces." == "Cleo allows you to create beautiful and testable command-line interfaces."
) )
foo = repository.packages[2] foo = repository.packages[3]
assert foo.name == "foo" assert foo.name == "foo"
assert foo.version.text == "0.1.0" assert foo.version.text == "0.1.0"
pendulum = repository.packages[3] pendulum = repository.packages[4]
assert pendulum.name == "pendulum" assert pendulum.name == "pendulum"
assert pendulum.version.text == "2.0.5" assert pendulum.version.text == "2.0.5"
assert pendulum.description == "Python datetimes made easy" assert pendulum.description == "Python datetimes made easy"
...@@ -71,8 +72,16 @@ def test_load(mocker): ...@@ -71,8 +72,16 @@ def test_load(mocker):
for pkg in repository.packages: for pkg in repository.packages:
assert pkg.name != "attrs" assert pkg.name != "attrs"
# test editable package with text .pth file
editable = repository.packages[1] editable = repository.packages[1]
assert "editable" == editable.name assert editable.name == "editable"
assert "2.3.4" == editable.version.text assert editable.version.text == "2.3.4"
assert "directory" == editable.source_type assert editable.source_type == "directory"
assert "/path/to/editable" == editable.source_url assert editable.source_url == Path("/path/to/editable").as_posix()
# test editable package with executable .pth file
editable = repository.packages[2]
assert editable.name == "editable-with-import"
assert editable.version.text == "2.3.4"
assert editable.source_type == ""
assert editable.source_url == ""
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