Skip to content

Commit

Permalink
Fixes installing lokal plugins with extras_require (for testing depen…
Browse files Browse the repository at this point in the history
…dencies mostly). Fixes lektor#865
  • Loading branch information
dwt committed Feb 11, 2021
1 parent 36bb3a7 commit 5f41271
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 4 deletions.
29 changes: 25 additions & 4 deletions lektor/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ def download_and_install_package(

def install_local_package(package_root, path):
"""This installs a local dependency of a package."""

# Becaus of these bugs:
# - pip https://github.com/pypa/pip/issues/4390
# - setuptools https://github.com/pypa/setuptools/issues/392
# we cannot just call `pip install --target $folder --editable $package`.
# Hence the workaround of first installing only the package and then it's dependencies

# XXX: windows
env = dict(os.environ)
env["PYTHONPATH"] = package_root
Expand Down Expand Up @@ -143,14 +150,28 @@ def install_local_package(package_root, path):
dirs = os.listdir(tmp)
if rv != 0 or len(dirs) != 1:
raise RuntimeError("Failed to create egg info for local package.")
requires = os.path.join(tmp, dirs[0], "requires.txt")
requires_path = os.path.join(tmp, dirs[0], "requires.txt")

if os.path.isfile(requires_path):
# We have dependencies, install them!
requirements_path = \
requiriements_txt_from_requires_file_in_same_directory(requires_path)
download_and_install_package(package_root, requirements_file=requirements_path)

# We have dependencies, install them!
if os.path.isfile(requires):
download_and_install_package(package_root, requirements_file=requires)
finally:
shutil.rmtree(tmp)

def requiriements_txt_from_requires_file_in_same_directory(requires_path):
"requirex.txt can contain [extras_require] sections wich pip doesn't understand"
requirements_path = os.path.join(os.path.dirname(requires_path), "requirements.txt")
with open(requirements_path, "w") as requirements, open(requires_path, 'r') as requires:
for line in requires.readlines():
# extra requires section starts here -> not valid requirements.txt syntax
if line.strip().startswith('['):
break
requirements.write(line)

return requirements_path

def get_package_info(path):
"""Returns the name of a package at a path."""
Expand Down
91 changes: 91 additions & 0 deletions tests/test_packages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import os
import shutil
import tempfile
import textwrap
import pathlib

import pytest

from lektor import packages

@pytest.fixture
def temp_dir():
with tempfile.TemporaryDirectory() as temp_dir:
yield pathlib.Path(temp_dir)


def create_plugin(package_dir, plugin_name, setup):
plugin_dir = package_dir / plugin_name
plugin_dir.mkdir(parents=True)
setup_py = plugin_dir / 'setup.py'
setup_py.write_text(textwrap.dedent(setup))
return plugin_dir


def test_install_local_package_with_dependency(temp_dir):
packages_dir = temp_dir / 'packages'
plugin_dir = create_plugin(packages_dir, 'dependency', setup="""
from setuptools import setup
setup(
name='dependency',
install_requires=['fluentpy']
)
"""
)

install_dir = temp_dir / 'target'
install_dir.mkdir()

packages.install_local_package(install_dir, plugin_dir)

assert (install_dir / 'dependency.egg-link').is_file()
assert (install_dir / 'fluentpy').is_dir()


def test_install_local_package_with_dependency_and_extras_require(temp_dir):
packages_dir = temp_dir / 'packages'
plugin_dir = create_plugin(packages_dir, 'dependency', setup="""
from setuptools import setup
setup(
name='dependency',
install_requires=['fluentpy'],
extras_require={
'test': ['pyexpect']
}
)
"""
)

install_dir = temp_dir / 'target'
install_dir.mkdir()

packages.install_local_package(install_dir, plugin_dir)

assert (install_dir / 'dependency.egg-link').is_file()
assert (install_dir / 'fluentpy').is_dir()
assert not (install_dir / 'pyexpect').is_dir()


def test_install_local_package_with_only_extras_require(temp_dir):
packages_dir = temp_dir / 'packages'
plugin_dir = create_plugin(packages_dir, 'extras_require', setup="""
from setuptools import setup
setup(
name='extras_require',
extras_require={
'test': ['pyexpect']
}
)
"""
)

install_dir = temp_dir / 'target'
install_dir.mkdir()

packages.install_local_package(install_dir, plugin_dir)

assert (install_dir / 'extras-require.egg-link').is_file()
assert not (install_dir / 'pyexpect').is_dir()

0 comments on commit 5f41271

Please sign in to comment.