mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
6ac1451ec8
* Move away from requirementslib models * Revise test since PEP-440 does not support wildcard versions but does support equivalent compatible release specifiers. * simplify and remove dead code * Ensure the os_name marker is AND with the other markers. * Move what we still need from requirementslib into the pipenv utils and stop vendoring it. * Remove requirementslib. * force upgrade of virtualenv for python 3.12 * remove virtualenv-clone * Update vcs specifiers documentation; infer name from specific pip line formats where possible. * Provide helpful text and error for recently removed commands * Set the right log levels and verbosity to show users the errors generated by pip resolver when supplying -v flag * Fix the collection of all matching package hashes for non-pypi indexes. Plus lesson from testing torch which contains local identifiers.
301 lines
9.8 KiB
Python
301 lines
9.8 KiB
Python
import json
|
|
import os
|
|
import pytest
|
|
|
|
from pipenv.utils.shell import temp_environ
|
|
from pipenv.utils.requirements import requirements_from_lockfile
|
|
|
|
|
|
@pytest.mark.requirements
|
|
def test_requirements_generates_requirements_from_lockfile(pipenv_instance_pypi):
|
|
with pipenv_instance_pypi() as p:
|
|
packages = ('requests', '2.14.0')
|
|
dev_packages = ('flask', '0.12.2')
|
|
with open(p.pipfile_path, 'w') as f:
|
|
contents = f"""
|
|
[packages]
|
|
{packages[0]}= "=={packages[1]}"
|
|
[dev-packages]
|
|
{dev_packages[0]}= "=={dev_packages[1]}"
|
|
""".strip()
|
|
f.write(contents)
|
|
p.pipenv('lock')
|
|
c = p.pipenv('requirements')
|
|
assert c.returncode == 0
|
|
assert f'{packages[0]}=={packages[1]}' in c.stdout
|
|
assert f'{dev_packages[0]}=={dev_packages[1]}' not in c.stdout
|
|
|
|
d = p.pipenv('requirements --dev')
|
|
assert d.returncode == 0
|
|
assert f'{packages[0]}=={packages[1]}' in d.stdout
|
|
assert f'{dev_packages[0]}=={dev_packages[1]}' in d.stdout
|
|
|
|
e = p.pipenv('requirements --dev-only')
|
|
assert e.returncode == 0
|
|
assert f'{packages[0]}=={packages[1]}' not in e.stdout
|
|
assert f'{dev_packages[0]}=={dev_packages[1]}' in e.stdout
|
|
|
|
e = p.pipenv('requirements --hash')
|
|
assert e.returncode == 0
|
|
assert f'{packages[0]}=={packages[1]}' in e.stdout
|
|
for value in p.lockfile['default'].values():
|
|
for hash in value['hashes']:
|
|
assert f' --hash={hash}' in e.stdout
|
|
|
|
|
|
@pytest.mark.requirements
|
|
def test_requirements_generates_requirements_from_lockfile_multiple_sources(pipenv_instance_private_pypi):
|
|
with pipenv_instance_private_pypi() as p:
|
|
packages = ('six', '1.12.0')
|
|
dev_packages = ('itsdangerous', '1.1.0')
|
|
with open(p.pipfile_path, 'w') as f:
|
|
contents = f"""
|
|
[[source]]
|
|
name = "pypi"
|
|
url = "https://pypi.org/simple"
|
|
verify_ssl = true
|
|
[[source]]
|
|
name = "other_source"
|
|
url = "https://some_other_source.org"
|
|
verify_ssl = true
|
|
[packages]
|
|
{packages[0]}= "=={packages[1]}"
|
|
[dev-packages]
|
|
{dev_packages[0]}= "=={dev_packages[1]}"
|
|
""".strip()
|
|
f.write(contents)
|
|
l = p.pipenv('lock')
|
|
assert l.returncode == 0
|
|
c = p.pipenv('requirements')
|
|
assert c.returncode == 0
|
|
|
|
assert '-i https://pypi.org/simple' in c.stdout
|
|
assert '--extra-index-url https://some_other_source.org' in c.stdout
|
|
|
|
|
|
@pytest.mark.requirements
|
|
def test_requirements_generates_requirements_from_lockfile_from_categories(pipenv_instance_private_pypi):
|
|
with pipenv_instance_private_pypi() as p:
|
|
packages = ('six', '1.12.0')
|
|
dev_packages = ('itsdangerous', '1.1.0')
|
|
test_packages = ('pytest', '7.1.3')
|
|
doc_packages = ('docutils', '0.19')
|
|
|
|
with open(p.pipfile_path, 'w') as f:
|
|
contents = f"""
|
|
[[source]]
|
|
name = "pypi"
|
|
url = "https://pypi.org/simple"
|
|
verify_ssl = true
|
|
[packages]
|
|
{packages[0]}= "=={packages[1]}"
|
|
[dev-packages]
|
|
{dev_packages[0]}= "=={dev_packages[1]}"
|
|
[test]
|
|
{test_packages[0]}= "=={test_packages[1]}"
|
|
[doc]
|
|
{doc_packages[0]}= "=={doc_packages[1]}"
|
|
""".strip()
|
|
f.write(contents)
|
|
l = p.pipenv('lock')
|
|
assert l.returncode == 0
|
|
|
|
c = p.pipenv('requirements --dev-only')
|
|
assert c.returncode == 0
|
|
assert f'{packages[0]}=={packages[1]}' not in c.stdout
|
|
assert f'{test_packages[0]}=={test_packages[1]}' not in c.stdout
|
|
assert f'{doc_packages[0]}=={doc_packages[1]}' not in c.stdout
|
|
assert f'{dev_packages[0]}=={dev_packages[1]}' in c.stdout
|
|
|
|
d = p.pipenv('requirements --categories="test, doc"')
|
|
assert d.returncode == 0
|
|
assert f'{packages[0]}=={packages[1]}' not in d.stdout
|
|
assert f'{dev_packages[0]}=={dev_packages[1]}' not in d.stdout
|
|
assert f'{test_packages[0]}=={test_packages[1]}' in d.stdout
|
|
assert f'{doc_packages[0]}=={doc_packages[1]}' in d.stdout
|
|
|
|
|
|
@pytest.mark.requirements
|
|
def test_requirements_with_git_requirements(pipenv_instance_pypi):
|
|
req_hash = '3264a0046e1aa3c0a813335286ebdbc651f58b13'
|
|
lockfile = {
|
|
"_meta": {"sources": []},
|
|
"default": {
|
|
"dataclasses-json": {
|
|
"editable": True,
|
|
"git": "https://github.com/lidatong/dataclasses-json.git",
|
|
"ref": req_hash
|
|
}
|
|
},
|
|
"develop": {}
|
|
}
|
|
|
|
with pipenv_instance_pypi() as p:
|
|
with open(p.lockfile_path, 'w') as f:
|
|
json.dump(lockfile, f)
|
|
|
|
c = p.pipenv('requirements')
|
|
assert c.returncode == 0
|
|
assert "dataclasses-json" in c.stdout
|
|
assert req_hash in c.stdout
|
|
|
|
|
|
@pytest.mark.requirements
|
|
def test_requirements_markers_get_included(pipenv_instance_pypi):
|
|
package, version, markers = "werkzeug", "==2.1.2", "python_version >= '3.7'"
|
|
lockfile = {
|
|
"_meta": {"sources": []},
|
|
"default": {
|
|
package: {
|
|
"hashes": [
|
|
"sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6",
|
|
"sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255"
|
|
],
|
|
"markers": markers,
|
|
"version": version
|
|
}
|
|
},
|
|
"develop": {}
|
|
}
|
|
|
|
with pipenv_instance_pypi() as p:
|
|
with open(p.lockfile_path, 'w') as f:
|
|
json.dump(lockfile, f)
|
|
|
|
c = p.pipenv('requirements')
|
|
assert c.returncode == 0
|
|
assert f'{package}{version}; {markers}' in c.stdout
|
|
|
|
|
|
@pytest.mark.requirements
|
|
def test_requirements_markers_get_excluded(pipenv_instance_pypi):
|
|
package, version, markers = "werkzeug", "==2.1.2", "python_version >= '3.7'"
|
|
lockfile = {
|
|
"_meta": {"sources": []},
|
|
"default": {
|
|
package: {
|
|
"hashes": [
|
|
"sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6",
|
|
"sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255"
|
|
],
|
|
"markers": markers,
|
|
"version": version
|
|
}
|
|
},
|
|
"develop": {}
|
|
}
|
|
|
|
with pipenv_instance_pypi() as p:
|
|
with open(p.lockfile_path, 'w') as f:
|
|
json.dump(lockfile, f)
|
|
|
|
c = p.pipenv('requirements --exclude-markers')
|
|
assert c.returncode == 0
|
|
assert markers not in c.stdout
|
|
|
|
|
|
@pytest.mark.requirements
|
|
def test_requirements_hashes_get_included(pipenv_instance_pypi):
|
|
package, version, markers = "werkzeug", "==2.1.2", "python_version >= '3.7'"
|
|
first_hash = "sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6"
|
|
second_hash = "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255"
|
|
lockfile = {
|
|
"_meta": {"sources": []},
|
|
"default": {
|
|
package: {
|
|
"hashes": [
|
|
first_hash,
|
|
second_hash
|
|
],
|
|
"markers": markers,
|
|
"version": version
|
|
}
|
|
},
|
|
"develop": {}
|
|
}
|
|
|
|
with pipenv_instance_pypi() as p:
|
|
with open(p.lockfile_path, 'w') as f:
|
|
json.dump(lockfile, f)
|
|
|
|
c = p.pipenv('requirements --hash')
|
|
assert c.returncode == 0
|
|
assert f'{package}{version}; {markers} --hash={first_hash} --hash={second_hash}' in c.stdout
|
|
|
|
|
|
def test_requirements_generates_requirements_from_lockfile_without_env_var_expansion(
|
|
pipenv_instance_pypi,
|
|
):
|
|
lockfile = {
|
|
"_meta": {
|
|
"sources": [
|
|
{
|
|
"name": "private_source",
|
|
"url": "https://${redacted_user}:${redacted_pwd}@private_source.org",
|
|
"verify_ssl": True,
|
|
}
|
|
]
|
|
},
|
|
"default": {},
|
|
}
|
|
|
|
with pipenv_instance_pypi() as p:
|
|
with open(p.lockfile_path, "w") as f:
|
|
json.dump(lockfile, f)
|
|
|
|
with temp_environ():
|
|
os.environ['redacted_user'] = "example_user"
|
|
os.environ['redacted_pwd'] = "example_pwd"
|
|
c = p.pipenv("requirements")
|
|
assert c.returncode == 0
|
|
|
|
assert (
|
|
"-i https://${redacted_user}:${redacted_pwd}@private_source.org"
|
|
in c.stdout
|
|
)
|
|
|
|
|
|
@pytest.mark.requirements
|
|
@pytest.mark.parametrize(
|
|
"deps, include_hashes, include_markers, expected",
|
|
[
|
|
(
|
|
{
|
|
"django-storages": {
|
|
"version": "==1.12.3",
|
|
"extras": ["azure"]
|
|
}
|
|
},
|
|
True,
|
|
True,
|
|
["django-storages[azure]==1.12.3"]
|
|
),
|
|
(
|
|
{
|
|
"evotum-cripto": {
|
|
"file": "https://gitlab.com/eVotUM/Cripto-py/-/archive/develop/Cripto-py-develop.zip"
|
|
}
|
|
},
|
|
True,
|
|
True,
|
|
["https://gitlab.com/eVotUM/Cripto-py/-/archive/develop/Cripto-py-develop.zip"]
|
|
),
|
|
(
|
|
{
|
|
"pyjwt": {
|
|
"git": "https://github.com/jpadilla/pyjwt.git",
|
|
"ref": "7665aa625506a11bae50b56d3e04413a3dc6fdf8",
|
|
"extras": ["crypto"]
|
|
}
|
|
},
|
|
True,
|
|
True,
|
|
["pyjwt[crypto]@ git+https://github.com/jpadilla/pyjwt.git@7665aa625506a11bae50b56d3e04413a3dc6fdf8"]
|
|
)
|
|
]
|
|
)
|
|
def test_requirements_from_deps(deps, include_hashes, include_markers, expected):
|
|
result = requirements_from_lockfile(deps, include_hashes, include_markers)
|
|
assert result == expected
|
|
|