2023-03-07 22:16:35 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
from e3.python.wheel import Wheel
|
|
|
|
|
from e3.os.process import Run
|
|
|
|
|
from e3.sys import python_script
|
|
|
|
|
from e3.fs import mkdir
|
2023-09-05 17:30:15 +02:00
|
|
|
from e3.python.pypi import PyPIClosure, PyPIError
|
|
|
|
|
|
2023-03-07 22:16:35 +01:00
|
|
|
import yaml
|
2024-01-24 19:02:44 +01:00
|
|
|
from os import listdir
|
|
|
|
|
from os.path import join as path_join, isfile, basename
|
2023-09-05 17:30:15 +02:00
|
|
|
import pytest
|
2023-03-07 22:16:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_py_pkg_source(
|
|
|
|
|
name: str, requires: list[str] | None = None, version="1.0.0"
|
2026-01-16 15:55:55 +00:00
|
|
|
) -> Wheel:
|
2023-03-07 22:16:35 +01:00
|
|
|
mkdir(name)
|
|
|
|
|
if requires:
|
|
|
|
|
requires_str = ",".join([f'"{el}"' for el in requires])
|
2024-01-24 19:02:44 +01:00
|
|
|
with open(path_join(name, "setup.py"), "w") as fd:
|
2023-03-07 22:16:35 +01:00
|
|
|
fd.write("from setuptools import setup, find_packages\n")
|
|
|
|
|
fd.write(f"setup(name='{name}',\n")
|
|
|
|
|
fd.write(f" version='{version}',\n")
|
|
|
|
|
if requires:
|
|
|
|
|
fd.write(f" install_requires=[{requires_str}],\n")
|
|
|
|
|
fd.write(" packages=find_packages())\n")
|
2024-01-24 19:02:44 +01:00
|
|
|
mkdir(path_join(name, name))
|
|
|
|
|
with open(path_join(name, name, "__init__.py"), "w") as fd:
|
2023-03-07 22:16:35 +01:00
|
|
|
fd.write(f"# This is package {name}")
|
2024-09-25 10:49:23 +02:00
|
|
|
return Wheel.build(
|
|
|
|
|
source_dir=name, dest_dir=".", build_args=["--no-build-isolation", "--no-index"]
|
|
|
|
|
)
|
2023-03-07 22:16:35 +01:00
|
|
|
|
|
|
|
|
|
2026-01-16 15:55:55 +00:00
|
|
|
def test_wheel() -> None:
|
2023-03-07 22:16:35 +01:00
|
|
|
wheel1 = generate_py_pkg_source("src1")
|
2024-01-24 19:02:44 +01:00
|
|
|
assert isfile(wheel1.path)
|
2023-03-07 22:16:35 +01:00
|
|
|
assert not wheel1.requirements
|
|
|
|
|
|
|
|
|
|
wheel2 = generate_py_pkg_source("src2", requires=["src1<=2.0.0"])
|
2024-01-24 19:02:44 +01:00
|
|
|
assert isfile(wheel2.path)
|
2023-03-07 22:16:35 +01:00
|
|
|
assert len(wheel2.requirements) == 1
|
|
|
|
|
|
|
|
|
|
mkdir(".cache")
|
|
|
|
|
|
|
|
|
|
with PyPIClosure(
|
2024-07-31 15:42:40 +02:00
|
|
|
python3_version="3.10",
|
2023-03-07 22:16:35 +01:00
|
|
|
platforms=[
|
|
|
|
|
"x86_64-linux",
|
|
|
|
|
"aarch64-linux",
|
|
|
|
|
"x86_64-windows",
|
|
|
|
|
"aarch64-darwin",
|
|
|
|
|
"x86_64-darwin",
|
|
|
|
|
],
|
|
|
|
|
cache_dir=".cache",
|
|
|
|
|
) as pypi:
|
|
|
|
|
pypi.add_wheel(wheel1.path)
|
|
|
|
|
pypi.add_wheel(wheel2.path)
|
|
|
|
|
pypi.add_requirement("src2==1.0.0")
|
|
|
|
|
pypi.add_requirement("src1<2.0.0")
|
|
|
|
|
pypi.add_requirement("src1>0.5.0")
|
|
|
|
|
pypi.add_requirement("src1>=0.6.0")
|
|
|
|
|
pypi.add_requirement("src1!=0.4.2")
|
2023-09-22 11:33:53 +02:00
|
|
|
pypi.add_requirement("src1~=1.0.0")
|
2023-03-07 22:16:35 +01:00
|
|
|
assert len(pypi.file_closure()) == 2
|
2024-07-31 15:42:40 +02:00
|
|
|
assert len(pypi.requirements_closure()) == 2
|
2023-03-07 22:16:35 +01:00
|
|
|
|
|
|
|
|
with PyPIClosure(
|
2024-07-31 15:42:40 +02:00
|
|
|
python3_version="3.10",
|
2023-03-07 22:16:35 +01:00
|
|
|
platforms=[
|
|
|
|
|
"x86_64-linux",
|
|
|
|
|
"aarch64-linux",
|
|
|
|
|
"x86_64-windows",
|
|
|
|
|
"aarch64-darwin",
|
|
|
|
|
"x86_64-darwin",
|
|
|
|
|
],
|
|
|
|
|
cache_dir=".cache",
|
|
|
|
|
) as pypi:
|
|
|
|
|
pypi.add_requirement("src2==1.0.0")
|
|
|
|
|
pypi.add_requirement("src1")
|
|
|
|
|
assert len(pypi.file_closure()) == 2
|
2024-07-31 15:42:40 +02:00
|
|
|
assert len(pypi.requirements_closure()) == 2
|
2023-03-07 22:16:35 +01:00
|
|
|
|
|
|
|
|
|
2026-01-16 15:55:55 +00:00
|
|
|
def test_pypi_closure_tool() -> None:
|
2023-03-07 22:16:35 +01:00
|
|
|
generate_py_pkg_source("src1")
|
|
|
|
|
generate_py_pkg_source("src2", requires=["src1<=2.0.0"])
|
|
|
|
|
with open("config.yml", "w") as fd:
|
|
|
|
|
fd.write(
|
|
|
|
|
yaml.safe_dump(
|
|
|
|
|
{
|
|
|
|
|
"wheels": {"src1": "ssh://url/src1", "src2": "ssh://url/src2"},
|
|
|
|
|
"platforms": ["x86_64-linux"],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
p = Run(
|
2026-02-03 14:32:00 +00:00
|
|
|
[
|
|
|
|
|
*python_script("e3-pypi-closure"),
|
2024-09-25 10:49:23 +02:00
|
|
|
"--python3-version=10",
|
|
|
|
|
"--local-clones=.",
|
|
|
|
|
"config.yml",
|
|
|
|
|
"dist",
|
|
|
|
|
"--wheel-build-arg=--no-build-isolation",
|
|
|
|
|
"--wheel-build-arg=--no-index",
|
|
|
|
|
]
|
2023-03-07 22:16:35 +01:00
|
|
|
)
|
|
|
|
|
assert p.status == 0, p.out
|
2024-01-24 19:02:44 +01:00
|
|
|
file_list = set(listdir("dist"))
|
2023-03-07 22:16:35 +01:00
|
|
|
assert file_list == {
|
|
|
|
|
"requirements.txt",
|
|
|
|
|
"src1-1.0.0-py3-none-any.whl",
|
|
|
|
|
"src2-1.0.0-py3-none-any.whl",
|
|
|
|
|
}
|
2023-09-05 17:30:15 +02:00
|
|
|
|
|
|
|
|
|
2026-01-16 15:55:55 +00:00
|
|
|
def test_star_requirements() -> None:
|
2023-09-05 17:30:15 +02:00
|
|
|
"""Test package requirements ending with * with != operator."""
|
|
|
|
|
wheel1 = generate_py_pkg_source("src1", version="1.0.4")
|
2024-01-24 19:02:44 +01:00
|
|
|
assert isfile(wheel1.path)
|
2023-09-05 17:30:15 +02:00
|
|
|
assert not wheel1.requirements
|
|
|
|
|
|
|
|
|
|
wheel2 = generate_py_pkg_source("src2", requires=["src1!=1.0.*"])
|
2024-01-24 19:02:44 +01:00
|
|
|
assert isfile(wheel2.path)
|
2023-09-05 17:30:15 +02:00
|
|
|
assert len(wheel2.requirements) == 1
|
|
|
|
|
|
|
|
|
|
wheel3 = generate_py_pkg_source("src1", version="1.1.4")
|
2024-01-24 19:02:44 +01:00
|
|
|
assert isfile(wheel3.path)
|
2023-09-05 17:30:15 +02:00
|
|
|
assert not wheel3.requirements
|
|
|
|
|
|
|
|
|
|
mkdir(".cache")
|
|
|
|
|
|
|
|
|
|
with PyPIClosure(
|
2024-07-31 15:42:40 +02:00
|
|
|
python3_version="3.10",
|
2023-09-05 17:30:15 +02:00
|
|
|
platforms=[
|
|
|
|
|
"x86_64-linux",
|
|
|
|
|
],
|
|
|
|
|
cache_dir=".cache",
|
|
|
|
|
) as pypi:
|
|
|
|
|
pypi.add_wheel(wheel1.path)
|
|
|
|
|
pypi.add_wheel(wheel2.path)
|
2024-07-31 15:42:40 +02:00
|
|
|
pypi.add_requirement("src2==1.0.0")
|
|
|
|
|
with pytest.raises(PyPIError, match="Impossible resolution"):
|
|
|
|
|
pypi.requirements_closure()
|
2023-09-05 17:30:15 +02:00
|
|
|
|
|
|
|
|
with PyPIClosure(
|
2024-07-31 15:42:40 +02:00
|
|
|
python3_version="3.10",
|
2023-09-05 17:30:15 +02:00
|
|
|
platforms=[
|
|
|
|
|
"x86_64-linux",
|
|
|
|
|
],
|
|
|
|
|
cache_dir=".cache",
|
|
|
|
|
) as pypi:
|
|
|
|
|
pypi.add_wheel(wheel2.path)
|
|
|
|
|
pypi.add_wheel(wheel3.path)
|
|
|
|
|
pypi.add_requirement("src2==1.0.0")
|
2024-07-31 15:42:40 +02:00
|
|
|
assert len(pypi.requirements_closure()) == 2
|
2024-01-24 13:52:42 +01:00
|
|
|
|
|
|
|
|
|
2024-01-24 19:02:44 +01:00
|
|
|
@pytest.mark.parametrize(
|
2026-01-21 12:59:07 +00:00
|
|
|
("arguments", "expected"),
|
2024-01-24 19:02:44 +01:00
|
|
|
[
|
|
|
|
|
((None, None), "setuptools_scm-7.1.0-py3-none-any.whl"),
|
|
|
|
|
((["setuptools-scm"], None), "setuptools_scm-8.0.0-py3-none-any.whl"),
|
|
|
|
|
((["setuptools_scm"], None), "setuptools_scm-8.0.0-py3-none-any.whl"),
|
|
|
|
|
((None, "setuptools_scm==8"), None),
|
|
|
|
|
],
|
|
|
|
|
)
|
2026-01-16 15:55:55 +00:00
|
|
|
def test_yanked(pypi_server, arguments, expected) -> None:
|
2024-01-24 19:02:44 +01:00
|
|
|
allowed_yanked, invalid_wheel = arguments
|
|
|
|
|
expected_wheel = expected
|
|
|
|
|
|
|
|
|
|
mkdir("cache")
|
|
|
|
|
|
2024-01-24 13:52:42 +01:00
|
|
|
with pypi_server:
|
2024-01-24 19:02:44 +01:00
|
|
|
with PyPIClosure(
|
2024-07-31 15:42:40 +02:00
|
|
|
python3_version="3.11",
|
2024-01-24 19:02:44 +01:00
|
|
|
platforms=[
|
|
|
|
|
"x86_64-linux",
|
|
|
|
|
],
|
|
|
|
|
cache_dir="cache",
|
|
|
|
|
allowed_yanked=allowed_yanked,
|
|
|
|
|
) as pypi:
|
|
|
|
|
if invalid_wheel:
|
2024-07-31 15:42:40 +02:00
|
|
|
pypi.add_requirement(invalid_wheel)
|
|
|
|
|
|
2024-01-24 19:02:44 +01:00
|
|
|
with pytest.raises(
|
|
|
|
|
PyPIError,
|
2024-07-31 15:42:40 +02:00
|
|
|
match=("Impossible resolution"),
|
2024-01-24 19:02:44 +01:00
|
|
|
):
|
2024-07-31 15:42:40 +02:00
|
|
|
pypi.requirements_closure()
|
2024-01-24 19:02:44 +01:00
|
|
|
else:
|
|
|
|
|
pypi.add_requirement("setuptools_scm >= 6.2, <= 8")
|
|
|
|
|
all_filenames = [basename(f) for f in pypi.file_closure()]
|
|
|
|
|
assert expected_wheel in all_filenames
|