from __future__ import absolute_import
import logging
from distutils import errors
import pkg_resources
import setuptools
try:
from pip.commands import install
except ImportError:
install = None
version_info = (1, 1, 0)
version = '.'.join(str(c) for c in version_info)
__version__ = version # compatibility shim
class PipInstall(setuptools.Command):
"""Install a requirements file using pip"""
command_name = 'requirements'
user_options = [
('find-links=', 'f', 'Find links at the given location/URL'),
('index-url=', 'i', 'Base URL of Python Package Index'),
('requirement-file=', 'r', 'Install requirements from file'),
('pre', None,
'Include pre-release or development versions of dependencies'),
('no-use-wheel', None, 'Do not find and prefer wheel archives'),
('install-test-requirements', 't', 'Install test_requires'),
('install-extra-requirements=', 'e',
'Install the requirements for the named "extra"'),
]
def initialize_options(self):
self._pip_args = []
self.find_links = None
self.index_url = None
self.install_extra_requirements = None
self.install_test_requirements = False
self.no_use_wheel = False
self.pre = False
self.requirement_file = None
def finalize_options(self):
requirements = []
if self.requirement_file is not None:
requirements.extend(['-r', self.requirement_file])
elif self.distribution.install_requires:
requirements.extend(self.distribution.install_requires)
if self.install_test_requirements:
requirements.extend(self.distribution.tests_require)
if (self.install_extra_requirements and
self.distribution.extras_require):
try:
requirements.extend(
self.distribution.extras_require[
self.install_extra_requirements])
except KeyError:
self.warn('{0} not found in extras_require - {1}'.format(
self.install_extra_requirements,
', '.join(self.distribution.extras_require.keys())
))
if not requirements: # no requirements, nothing to do here
return
self._pip_args.extend(requirements)
if self.find_links is not None:
self._pip_args.extend(['-f', self.find_links])
if self.index_url is not None:
self._pip_args.extend(['-i', self.index_url])
if self.no_use_wheel:
self._pip_args.append('--no-use-wheel')
if self.pre:
self._pip_args.append('--pre')
def run(self):
if install is None:
raise errors.DistutilsSetupError(
'could not find pip.install module')
if self._pip_args:
cmd = install.InstallCommand()
args = cmd.cmd_opts.parser.parse_args(self._pip_args)
cmd.run(*args)
else:
self.warn('no requirements to install')
PipInstall.description = PipInstall.__doc__.splitlines()[0]
[docs]def read_requirements_from_file(file_name):
"""Read requirements from a pip-formatted requirements file.
:param str file_name: the name of the file to read from
:return: a ``list`` of requirements as strings
This function reads the specified file, processes it as the
:command:`pip` utility would, and returns the list of
dependency specifiers. Each line of the requirements file
is parsed using the functionality provided by `pkg_resources`_
so even the hairiest dependency specifiers will be parsed
correctly. However, all command line parameter overrides (e.g.,
``--index-file=...``) are ignored.
.. _pkg_resources:
https://setuptools.readthedocs.io/en/latest
/pkg_resources.html#requirements-parsing
"""
logger = logging.getLogger('read_requirements_from_file')
requirements = []
with open(file_name, 'rb') as req_file:
for line_number, buf in enumerate(req_file):
line = buf.decode('utf-8').strip()
if line.find('#') >= 0:
line = line[0:line.find('#')].strip()
if not line:
continue
if line.startswith('-'):
continue
try:
req = pkg_resources.Requirement.parse(line)
requirements.append(str(req))
except ValueError:
logger.warning(
'failed to parse line %s in %s',
line_number, file_name,
exc_info=True,
)
return requirements