Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add support for "requires" key in Python install config and allow extra keys beginning with "x-" #7259

Closed
wants to merge 5 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add support for "requires" key to Python "install" config
NiklasRosenstein committed Jul 3, 2020
commit f0c4909350c51ad7db50287a93c53173a0ce2827
21 changes: 21 additions & 0 deletions docs/config-file/v2.rst
Original file line number Diff line number Diff line change
@@ -175,6 +175,27 @@ Example:
manage the build, this setting will not have any effect. Instead
add the extra requirements to the ``environment`` file of Conda.

Requirements List
'''''''''''''''''

Install packages from a list of requirements as a string (similar to how they would be
listed on the command-line when invoking ``pip install``).

:Key: `requires`
:Type: ``string``
:Required: ``true``

Example:

.. code-block:: yaml

version: 2

python:
version: 3.7
install:
- requires: mkdocs-material Pygments

Packages
''''''''

6 changes: 6 additions & 0 deletions readthedocs/config/config.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
import copy
import os
import re
import shlex
from contextlib import contextmanager

from django.conf import settings
@@ -833,6 +834,9 @@ def validate_python_install(self, index):
self.base_path,
)
python_install['requirements'] = requirements
elif 'requires' in raw_install:
requires_key = key + 'requires'
python_install['requires'] = shlex.split(self.pop_config(requires_key))
elif 'path' in raw_install:
path_key = key + '.path'
with self.catch_validation_error(path_key):
@@ -1113,6 +1117,8 @@ def python(self):
for install in python['install']:
if 'requirements' in install:
python_install.append(PythonInstallRequirements(**install),)
elif 'requires' in install:
python_install.append(PythonInstallRequirementsList(install['requires']))
elif 'path' in install:
python_install.append(PythonInstall(**install),)
return Python(
5 changes: 5 additions & 0 deletions readthedocs/config/models.py
Original file line number Diff line number Diff line change
@@ -41,6 +41,11 @@ class PythonInstallRequirements(Base):
__slots__ = ('requirements',)


class PythonInstallRequirementsList(Base):

__slots__ = ('requirements',)


class PythonInstall(Base):

__slots__ = (
18 changes: 18 additions & 0 deletions readthedocs/config/tests/test_config.py
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
Conda,
PythonInstall,
PythonInstallRequirements,
PythonInstallRequirementsList,
)
from readthedocs.config.validation import (
INVALID_BOOL,
@@ -1104,6 +1105,23 @@ def test_python_install_requirements_check_valid(self, tmpdir):
assert isinstance(install[0], PythonInstallRequirements)
assert install[0].requirements == 'requirements.txt'

def test_python_install_requires_check_valid(self, tmpdir):
build = self.get_build_config(
{
'python': {
'install': [{
'requires': 'package_a "package_b >=3.0.0,<4.0.0"',
}],
},
},
source_file=str(tmpdir.join('readthedocs.yml')),
)
build.validate()
install = build.python.install
assert len(install) == 1
assert isinstance(install[0], PythonInstallRequirementsList)
assert install[0].requirements == ['package_a', 'package_b >=3.0.0,<4.0.0']

def test_python_install_requirements_does_not_allow_null(self, tmpdir):
build = self.get_build_config(
{
29 changes: 29 additions & 0 deletions readthedocs/doc_builder/python_environments.py
Original file line number Diff line number Diff line change
@@ -77,6 +77,8 @@ def install_requirements(self):
for install in self.config.python.install:
if isinstance(install, PythonInstallRequirements):
self.install_requirements_file(install)
if isinstance(install, PythonInstallRequirementsString):
self.install_requirements_string(install)
if isinstance(install, PythonInstall):
self.install_package(install)

@@ -430,6 +432,33 @@ def install_requirements_file(self, install):
bin_path=self.venv_bin(),
)

def install_requirements_string(self, install):
"""
Install requirements from a string specification using pip.

:param install: A instal object from the config module.
:type install: readthedocs.config.modules.PythonInstallRequirementsString
"""

args = [
self.venv_bin(filename='python'),
'-m',
'pip',
'install',
]
if self.project.has_feature(Feature.PIP_ALWAYS_UPGRADE):
args += ['--upgrade']
args += [
'--exists-action=w',
*self._pip_cache_cmd_argument(),
]
args += install.requirements
self.build_env.run(
*args,
cwd=self.checkout_path,
bin_path=self.venv_bin(),
)

def list_packages_installed(self):
"""List packages installed in pip."""
args = [