RequirementsLib: Requirement Management Library for Pip and Pipenv
Install from PyPI:
$ pipenv install requirementslib
Install from Github:
$ pipenv install -e git+https://github.com/sarugaku/requirementslib.git#egg=requirementslib
RequirementsLib provides a simple layer for building and interacting with requirements in both the Pipfile format and the requirements.txt format. This library was originally built for converting between these formats in Pipenv.
You can use RequirementsLib to import your lockfile into your setup file for including your install_requires dependencies:
from requirementslib import Lockfile
lockfile = Lockfile.create('/path/to/project/dir')
install_requires = lockfile.as_requirements(dev=False)
You can also interact directly with a Pipfile:
>>> from requirementslib import Pipfile
>>> pf = Pipfile.load('/home/hawk/git/pypa-pipenv')
>>> pf.sections
[Section(name='packages', requirements=[]), Section(name='dev-packages', requirements=[Requirement(name='pipenv', vcs=None, req=FileRequirement(setup_path=None, path='.', editable=True, uri='file:///home/hawk/git/pypa-pipenv', link=<Link file:///home/hawk/git/pypa-pipenv>, name='pipenv', req=<Requirement: "-e file:///home/hawk/git/pypa-pipenv">), markers='', specifiers=None, index=None, editable=True, hashes=[], extras=None),...]
And you can even write it back out into Pipfile's native format:
>>> print(pf.dump(to_dict=False))
[packages]
[dev-packages]
pipenv = {path = ".", editable = true}
flake8 = ">=3.3.0,<4"
pytest = "*"
mock = "*"
[scripts]
tests = "bash ./run-tests.sh"
[pipenv]
allow_prereleases = true
>>> from requirementslib import Requirement
>>> r = Requirement.from_line('-e git+https://github.com/pypa/pipenv.git@master#egg=pipenv')
>>> print(r)
Requirement(name='pipenv', vcs='git', req=VCSRequirement(editable=True, uri='git+https://github.com/pypa/pipenv.git', path=None, vcs='git', ref='master', subdirectory=None, name='pipenv', link=<Link git+https://github.com/pypa/pipenv.git@master#egg=pipenv>, req=<Requirement: "-e git+https://github.com/pypa/pipenv.git@master#egg=pipenv">), markers=None, specifiers=None, index=None, editable=True, hashes=[], extras=[])
>>> r.as_pipfile()
{'pipenv': {'editable': True, 'ref': 'master', 'git': 'https://github.com/pypa/pipenv.git'}}
Or move from Pipfile format to requirements.txt:
>>> r = Requirement.from_pipfile(name='pythonfinder', indexes=[], pipfile={'path': '../pythonfinder', 'editable': True})
>>> r.as_line()
'-e ../pythonfinder'
Requirementslib also can resolve the dependencies of editable packages by calling the run_requires
method.
This method returns a detailed dictionary containing metadata parsed from the package built in
a transient folder (unless it is already on the system or the call is run in a virtualenv).
The output of run_requires
is very detailed and in most cases will be sufficient:
>>> from pprint import pprint
>>> from requirementslib.models.requirements import Requirement
>>> r = Requirement.from_line("-e [email protected]:sarugaku/vistir.git#egg=vistir[spinner]")
>>> setup_info_dict = r.run_requires()
>>> from pprint import pprint
>>> pprint(setup_info_dict)
{'base_dir': '/tmp/requirementslib-t_ftl6no-src/src/vistir',
'build_backend': 'setuptools.build_meta',
'build_requires': ['setuptools>=36.2.2', 'wheel>=0.28.0'],
'extra_kwargs': {'build_dir': '/tmp/requirementslib-t_ftl6no-src/src',
'download_dir': '/home/hawk/.cache/pipenv/pkgs',
'src_dir': '/tmp/requirementslib-t_ftl6no-src/src',
'wheel_download_dir': '/home/hawk/.cache/pipenv/wheels'},
'extras': {'spinner': [Requirement.parse('cursor'),
Requirement.parse('yaspin')],
'tests': [Requirement.parse('pytest'),
Requirement.parse('pytest-xdist'),
Requirement.parse('pytest-cov'),
Requirement.parse('pytest-timeout'),
Requirement.parse('hypothesis-fspaths'),
Requirement.parse('hypothesis')]},
'ireq': <InstallRequirement object: vistir[spinner] from git+ssh://[email protected]/sarugaku/vistir.git#egg=vistir editable=True>,
'name': 'vistir',
'pyproject': PosixPath('/tmp/requirementslib-t_ftl6no-src/src/vistir/pyproject.toml'),
'python_requires': '>=2.6,!=3.0,!=3.1,!=3.2,!=3.3',
'requires': {'backports.functools_lru_cache;python_version<="3.4"': Requirement.parse('backports.functools_lru_cache; python_version <= "3.4"'),
'backports.shutil_get_terminal_size;python_version<"3.3"': Requirement.parse('backports.shutil_get_terminal_size; python_version < "3.3"'),
'backports.weakref;python_version<"3.3"': Requirement.parse('backports.weakref; python_version < "3.3"'),
'colorama': Requirement.parse('colorama'),
'pathlib2;python_version<"3.5"': Requirement.parse('pathlib2; python_version < "3.5"'),
'requests': Requirement.parse('requests'),
'six': Requirement.parse('six'),
'spinner': [Requirement.parse('cursor'),
Requirement.parse('yaspin')]},
'setup_cfg': PosixPath('/tmp/requirementslib-t_ftl6no-src/src/vistir/setup.cfg'),
'setup_py': PosixPath('/tmp/requirementslib-t_ftl6no-src/src/vistir/setup.py')}
As a side-effect of calls to run_requires
, new metadata is made available on the
requirement itself via the property requirement.req.dependencies
:
>>> pprint(r.req.dependencies)
({'backports.functools_lru_cache;python_version<="3.4"': Requirement.parse('backports.functools_lru_cache; python_version <= "3.4"'),
'backports.shutil_get_terminal_size;python_version<"3.3"': Requirement.parse('backports.shutil_get_terminal_size; python_version < "3.3"'),
'backports.weakref;python_version<"3.3"': Requirement.parse('backports.weakref; python_version < "3.3"'),
'colorama': Requirement.parse('colorama'),
'pathlib2;python_version<"3.5"': Requirement.parse('pathlib2; python_version < "3.5"'),
'requests': Requirement.parse('requests'),
'six': Requirement.parse('six'),
'spinner': [Requirement.parse('cursor'), Requirement.parse('yaspin')]},
[],
['setuptools>=36.2.2', 'wheel>=0.28.0'])