Commit abee30f0 by Sébastien Eustace Committed by GitHub

Fix editable installations (#2400)

parent e70ee311
import os
import tempfile
from io import open
from subprocess import CalledProcessError
from clikit.api.io import IO
......@@ -177,7 +176,6 @@ class PipInstaller(BaseInstaller):
def install_directory(self, package):
from poetry.factory import Factory
from poetry.io.null_io import NullIO
from poetry.utils._compat import decode
from poetry.masonry.builders.editable import EditableBuilder
from poetry.utils.toml_file import TomlFile
......@@ -208,40 +206,39 @@ class PipInstaller(BaseInstaller):
and pip_version >= pip_version_with_build_system_support
)
setup = os.path.join(req, "setup.py")
has_setup = os.path.exists(setup)
if has_poetry and package.develop and not package.build_script:
# This is a Poetry package in editable mode
# we can use the EditableBuilder without going through pip
# to install it, unless it has a build script.
builder = EditableBuilder(
Factory().create_poetry(pyproject.parent), self._env, NullIO()
)
builder.build()
if has_poetry:
package_poetry = Factory().create_poetry(pyproject.parent)
if package.develop and not package_poetry.package.build_script:
# This is a Poetry package in editable mode
# we can use the EditableBuilder without going through pip
# to install it, unless it has a build script.
builder = EditableBuilder(package_poetry, self._env, NullIO())
builder.build()
return
elif has_poetry and (not has_build_system or package.build_script):
from poetry.core.masonry.builders.sdist import SdistBuilder
return
elif not has_build_system or package_poetry.package.build_script:
from poetry.core.masonry.builders.sdist import SdistBuilder
# We need to rely on creating a temporary setup.py
# file since the version of pip does not support
# build-systems
# We also need it for non-PEP-517 packages
builder = SdistBuilder(package_poetry)
# We need to rely on creating a temporary setup.py
# file since the version of pip does not support
# build-systems
# We also need it for non-PEP-517 packages
builder = SdistBuilder(Factory().create_poetry(pyproject.parent))
with builder.setup_py():
if package.develop:
args.append("-e")
with open(setup, "w", encoding="utf-8") as f:
f.write(decode(builder.build_setup()))
args.append(req)
return self.run(*args)
if package.develop:
args.append("-e")
args.append(req)
try:
return self.run(*args)
finally:
if not has_setup and os.path.exists(setup):
os.remove(setup)
return self.run(*args)
def install_git(self, package):
from poetry.core.packages import Package
......
......@@ -16,7 +16,7 @@ from poetry.utils._compat import decode
SCRIPT_TEMPLATE = """\
#!{python}
from {module} import {callable_}
from {module} import {callable_holder}
if __name__ == '__main__':
{callable_}()
......@@ -105,6 +105,8 @@ class EditableBuilder(Builder):
for script in scripts:
name, script = script.split(" = ")
module, callable_ = script.split(":")
callable_holder = callable_.rsplit(".", 1)[0]
script_file = scripts_path.joinpath(name)
self._debug(
" - Adding the <c2>{}</c2> script to <b>{}</b>".format(
......@@ -117,6 +119,7 @@ class EditableBuilder(Builder):
SCRIPT_TEMPLATE.format(
python=self._env._bin("python"),
module=module,
callable_holder=callable_holder,
callable_=callable_,
)
)
......
......@@ -49,6 +49,19 @@ class InstalledRepository(Repository):
is_standard_package = False
if is_standard_package:
if (
path.name.endswith(".dist-info")
and env.site_packages.joinpath(
"{}.pth".format(package.pretty_name)
).exists()
):
with env.site_packages.joinpath(
"{}.pth".format(package.pretty_name)
).open() as f:
directory = Path(f.readline().strip())
package.source_type = "directory"
package.source_url = directory.as_posix()
continue
src_path = env.path / "src"
......
......@@ -26,3 +26,4 @@ python = "~2.7 || ^3.4"
[tool.poetry.scripts]
foo = "foo:bar"
baz = "bar:baz.boom.bim"
......@@ -70,7 +70,7 @@ def test_builder_installs_proper_files_for_standard_packages(simple_poetry, tmp_
assert "poetry" == dist_info.joinpath("INSTALLER").read_text()
assert (
"[console_scripts]\nfoo=foo:bar\n\n"
"[console_scripts]\nbaz=bar:baz.boom.bim\nfoo=foo:bar\n\n"
== dist_info.joinpath("entry_points.txt").read_text()
)
......@@ -109,11 +109,36 @@ My Package
records = dist_info.joinpath("RECORD").read_text()
assert str(tmp_venv.site_packages.joinpath("simple_project.pth")) 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
assert str(dist_info.joinpath("INSTALLER")) in records
assert str(dist_info.joinpath("entry_points.txt")) in records
assert str(dist_info.joinpath("RECORD")) in records
baz_script = """\
#!{python}
from bar import baz.boom
if __name__ == '__main__':
baz.boom.bim()
""".format(
python=tmp_venv._bin("python")
)
assert baz_script == tmp_venv._bin_dir.joinpath("baz").read_text()
foo_script = """\
#!{python}
from foo import bar
if __name__ == '__main__':
bar()
""".format(
python=tmp_venv._bin("python")
)
assert foo_script == tmp_venv._bin_dir.joinpath("foo").read_text()
def test_builder_falls_back_on_setup_and_pip_for_packages_with_build_scripts(
extended_poetry,
......
Metadata-Version: 2.1
Name: editable
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
####
......@@ -17,6 +17,7 @@ INSTALLED_RESULTS = [
zipp.Path(str(SITE_PACKAGES / "foo-0.1.0-py3.8.egg"), "EGG-INFO")
),
metadata.PathDistribution(VENDOR_DIR / "attrs-19.3.0.dist-info"),
metadata.PathDistribution(SITE_PACKAGES / "editable-2.3.4.dist-info"),
]
......@@ -45,7 +46,7 @@ def test_load(mocker):
mocker.patch("poetry.repositories.installed_repository._VENDORS", str(VENDOR_DIR))
repository = InstalledRepository.load(MockEnv(path=ENV_DIR))
assert len(repository.packages) == 3
assert len(repository.packages) == 4
cleo = repository.packages[0]
assert cleo.name == "cleo"
......@@ -55,11 +56,11 @@ def test_load(mocker):
== "Cleo allows you to create beautiful and testable command-line interfaces."
)
foo = repository.packages[1]
foo = repository.packages[2]
assert foo.name == "foo"
assert foo.version.text == "0.1.0"
pendulum = repository.packages[2]
pendulum = repository.packages[3]
assert pendulum.name == "pendulum"
assert pendulum.version.text == "2.0.5"
assert pendulum.description == "Python datetimes made easy"
......@@ -69,3 +70,9 @@ def test_load(mocker):
for pkg in repository.packages:
assert pkg.name != "attrs"
editable = repository.packages[1]
assert "editable" == editable.name
assert "2.3.4" == editable.version.text
assert "directory" == editable.source_type
assert "/path/to/editable" == 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