test_info.py (poetry-1.1.15) | : | test_info.py (poetry-1.2.0) | ||
---|---|---|---|---|
from typing import Set | from __future__ import annotations | |||
from pathlib import Path | ||||
from subprocess import CalledProcessError | ||||
from typing import TYPE_CHECKING | ||||
import pytest | import pytest | |||
from poetry.inspection.info import PackageInfo | from poetry.inspection.info import PackageInfo | |||
from poetry.inspection.info import PackageInfoError | from poetry.inspection.info import PackageInfoError | |||
from poetry.utils._compat import PY35 | ||||
from poetry.utils._compat import CalledProcessError | ||||
from poetry.utils._compat import Path | ||||
from poetry.utils._compat import decode | from poetry.utils._compat import decode | |||
from poetry.utils.env import EnvCommandError | from poetry.utils.env import EnvCommandError | |||
from poetry.utils.env import VirtualEnv | from poetry.utils.env import VirtualEnv | |||
if TYPE_CHECKING: | ||||
from pytest_mock import MockerFixture | ||||
FIXTURE_DIR_BASE = Path(__file__).parent.parent / "fixtures" | FIXTURE_DIR_BASE = Path(__file__).parent.parent / "fixtures" | |||
FIXTURE_DIR_INSPECTIONS = FIXTURE_DIR_BASE / "inspection" | FIXTURE_DIR_INSPECTIONS = FIXTURE_DIR_BASE / "inspection" | |||
@pytest.fixture(autouse=True) | @pytest.fixture(autouse=True) | |||
def pep517_metadata_mock(): | def pep517_metadata_mock(): | |||
pass | pass | |||
@pytest.fixture | @pytest.fixture | |||
def demo_sdist(): # type: () -> Path | def demo_sdist() -> Path: | |||
return FIXTURE_DIR_BASE / "distributions" / "demo-0.1.0.tar.gz" | return FIXTURE_DIR_BASE / "distributions" / "demo-0.1.0.tar.gz" | |||
@pytest.fixture | @pytest.fixture | |||
def demo_wheel(): # type: () -> Path | def demo_wheel() -> Path: | |||
return FIXTURE_DIR_BASE / "distributions" / "demo-0.1.0-py2.py3-none-any.whl " | return FIXTURE_DIR_BASE / "distributions" / "demo-0.1.0-py2.py3-none-any.whl " | |||
@pytest.fixture | @pytest.fixture | |||
def source_dir(tmp_path): # type: (Path) -> Path | def source_dir(tmp_path: Path) -> Path: | |||
yield Path(tmp_path.as_posix()) | return Path(tmp_path.as_posix()) | |||
@pytest.fixture | @pytest.fixture | |||
def demo_setup(source_dir): # type: (Path) -> Path | def demo_setup(source_dir: Path) -> Path: | |||
setup_py = source_dir / "setup.py" | setup_py = source_dir / "setup.py" | |||
setup_py.write_text( | setup_py.write_text( | |||
decode( | decode( | |||
"from setuptools import setup; " | "from setuptools import setup; " | |||
'setup(name="demo", ' | 'setup(name="demo", ' | |||
'version="0.1.0", ' | 'version="0.1.0", ' | |||
'install_requires=["package"])' | 'install_requires=["package"])' | |||
) | ) | |||
) | ) | |||
yield source_dir | return source_dir | |||
@pytest.fixture | @pytest.fixture | |||
def demo_setup_cfg(source_dir): # type: (Path) -> Path | def demo_setup_cfg(source_dir: Path) -> Path: | |||
setup_cfg = source_dir / "setup.cfg" | setup_cfg = source_dir / "setup.cfg" | |||
setup_cfg.write_text( | setup_cfg.write_text( | |||
decode( | decode( | |||
"\n".join( | "\n".join( | |||
[ | [ | |||
"[metadata]", | "[metadata]", | |||
"name = demo", | "name = demo", | |||
"version = 0.1.0", | "version = 0.1.0", | |||
"[options]", | "[options]", | |||
"install_requires = package", | "install_requires = package", | |||
] | ] | |||
) | ) | |||
) | ) | |||
) | ) | |||
yield source_dir | return source_dir | |||
@pytest.fixture | @pytest.fixture | |||
def demo_setup_complex(source_dir): # type: (Path) -> Path | def demo_setup_complex(source_dir: Path) -> Path: | |||
setup_py = source_dir / "setup.py" | setup_py = source_dir / "setup.py" | |||
setup_py.write_text( | setup_py.write_text( | |||
decode( | decode( | |||
"from setuptools import setup; " | "from setuptools import setup; " | |||
'setup(name="demo", ' | 'setup(name="demo", ' | |||
'version="0.1.0", ' | 'version="0.1.0", ' | |||
'install_requires=[i for i in ["package"]])' | 'install_requires=[i for i in ["package"]])' | |||
) | ) | |||
) | ) | |||
yield source_dir | return source_dir | |||
@pytest.fixture | @pytest.fixture | |||
def demo_setup_complex_pep517_legacy(demo_setup_complex): # type: (Path) -> Pat h | def demo_setup_complex_pep517_legacy(demo_setup_complex: Path) -> Path: | |||
pyproject_toml = demo_setup_complex / "pyproject.toml" | pyproject_toml = demo_setup_complex / "pyproject.toml" | |||
pyproject_toml.write_text( | pyproject_toml.write_text( | |||
decode("[build-system]\n" 'requires = ["setuptools", "wheel"]') | decode('[build-system]\nrequires = ["setuptools", "wheel"]') | |||
) | ) | |||
yield demo_setup_complex | return demo_setup_complex | |||
def demo_check_info(info, requires_dist=None): # type: (PackageInfo, Set[str]) -> None | def demo_check_info(info: PackageInfo, requires_dist: set[str] = None) -> None: | |||
assert info.name == "demo" | assert info.name == "demo" | |||
assert info.version == "0.1.0" | assert info.version == "0.1.0" | |||
assert info.requires_dist | assert info.requires_dist | |||
requires_dist = requires_dist or { | requires_dist = requires_dist or { | |||
'cleo; extra == "foo"', | 'cleo; extra == "foo"', | |||
"pendulum (>=1.4.4)", | "pendulum (>=1.4.4)", | |||
'tomlkit; extra == "bar"', | 'tomlkit; extra == "bar"', | |||
} | } | |||
assert set(info.requires_dist) == requires_dist | assert set(info.requires_dist) == requires_dist | |||
def test_info_from_sdist(demo_sdist): | def test_info_from_sdist(demo_sdist: Path): | |||
info = PackageInfo.from_sdist(demo_sdist) | info = PackageInfo.from_sdist(demo_sdist) | |||
demo_check_info(info) | demo_check_info(info) | |||
def test_info_from_wheel(demo_wheel): | def test_info_from_wheel(demo_wheel: Path): | |||
info = PackageInfo.from_wheel(demo_wheel) | info = PackageInfo.from_wheel(demo_wheel) | |||
demo_check_info(info) | demo_check_info(info) | |||
def test_info_from_bdist(demo_wheel): | def test_info_from_bdist(demo_wheel: Path): | |||
info = PackageInfo.from_bdist(demo_wheel) | info = PackageInfo.from_bdist(demo_wheel) | |||
demo_check_info(info) | demo_check_info(info) | |||
def test_info_from_poetry_directory(): | def test_info_from_poetry_directory(): | |||
info = PackageInfo.from_directory( | info = PackageInfo.from_directory( | |||
FIXTURE_DIR_INSPECTIONS / "demo", disable_build=True | FIXTURE_DIR_INSPECTIONS / "demo", disable_build=True | |||
) | ) | |||
demo_check_info(info) | demo_check_info(info) | |||
def test_info_from_poetry_directory_fallback_on_poetry_create_error(mocker): | def test_info_from_poetry_directory_fallback_on_poetry_create_error( | |||
mocker: MockerFixture, | ||||
): | ||||
mock_create_poetry = mocker.patch( | mock_create_poetry = mocker.patch( | |||
"poetry.inspection.info.Factory.create_poetry", side_effect=RuntimeError | "poetry.inspection.info.Factory.create_poetry", side_effect=RuntimeError | |||
) | ) | |||
mock_get_poetry_package = mocker.spy(PackageInfo, "_get_poetry_package") | mock_get_poetry_package = mocker.spy(PackageInfo, "_get_poetry_package") | |||
mock_get_pep517_metadata = mocker.patch( | mock_get_pep517_metadata = mocker.patch( | |||
"poetry.inspection.info.PackageInfo._pep517_metadata" | "poetry.inspection.info.get_pep517_metadata" | |||
) | ) | |||
PackageInfo.from_directory(FIXTURE_DIR_INSPECTIONS / "demo_poetry_package") | PackageInfo.from_directory(FIXTURE_DIR_INSPECTIONS / "demo_poetry_package") | |||
assert mock_create_poetry.call_count == 1 | assert mock_create_poetry.call_count == 1 | |||
assert mock_get_poetry_package.call_count == 1 | assert mock_get_poetry_package.call_count == 1 | |||
assert mock_get_pep517_metadata.call_count == 1 | assert mock_get_pep517_metadata.call_count == 1 | |||
def test_info_from_requires_txt(): | def test_info_from_requires_txt(): | |||
info = PackageInfo.from_metadata( | info = PackageInfo.from_metadata( | |||
FIXTURE_DIR_INSPECTIONS / "demo_only_requires_txt.egg-info" | FIXTURE_DIR_INSPECTIONS / "demo_only_requires_txt.egg-info" | |||
) | ) | |||
demo_check_info(info) | demo_check_info(info) | |||
@pytest.mark.skipif(not PY35, reason="Parsing of setup.py is skipped for Python | def test_info_from_setup_py(demo_setup: Path): | |||
< 3.5") | ||||
def test_info_from_setup_py(demo_setup): | ||||
info = PackageInfo.from_setup_files(demo_setup) | info = PackageInfo.from_setup_files(demo_setup) | |||
demo_check_info(info, requires_dist={"package"}) | demo_check_info(info, requires_dist={"package"}) | |||
@pytest.mark.skipif(not PY35, reason="Parsing of setup.cfg is skipped for Python | def test_info_from_setup_cfg(demo_setup_cfg: Path): | |||
< 3.5") | ||||
def test_info_from_setup_cfg(demo_setup_cfg): | ||||
info = PackageInfo.from_setup_files(demo_setup_cfg) | info = PackageInfo.from_setup_files(demo_setup_cfg) | |||
demo_check_info(info, requires_dist={"package"}) | demo_check_info(info, requires_dist={"package"}) | |||
def test_info_no_setup_pkg_info_no_deps(): | def test_info_no_setup_pkg_info_no_deps(): | |||
info = PackageInfo.from_directory( | info = PackageInfo.from_directory( | |||
FIXTURE_DIR_INSPECTIONS / "demo_no_setup_pkg_info_no_deps", disable_buil | FIXTURE_DIR_INSPECTIONS / "demo_no_setup_pkg_info_no_deps", | |||
d=True, | disable_build=True, | |||
) | ) | |||
assert info.name == "demo" | assert info.name == "demo" | |||
assert info.version == "0.1.0" | assert info.version == "0.1.0" | |||
assert info.requires_dist is None | assert info.requires_dist is None | |||
@pytest.mark.skipif(not PY35, reason="Parsing of setup.py is skipped for Python | def test_info_setup_simple(mocker: MockerFixture, demo_setup: Path): | |||
< 3.5") | ||||
def test_info_setup_simple(mocker, demo_setup): | ||||
spy = mocker.spy(VirtualEnv, "run") | spy = mocker.spy(VirtualEnv, "run") | |||
info = PackageInfo.from_directory(demo_setup) | info = PackageInfo.from_directory(demo_setup) | |||
assert spy.call_count == 0 | assert spy.call_count == 0 | |||
demo_check_info(info, requires_dist={"package"}) | demo_check_info(info, requires_dist={"package"}) | |||
@pytest.mark.skipif( | def test_info_setup_cfg(mocker: MockerFixture, demo_setup_cfg: Path): | |||
PY35, | ||||
reason="For projects with setup.py using Python < 3.5 fallback to pep517 bui | ||||
ld", | ||||
) | ||||
def test_info_setup_simple_py2(mocker, demo_setup): | ||||
spy = mocker.spy(VirtualEnv, "run") | ||||
info = PackageInfo.from_directory(demo_setup) | ||||
assert spy.call_count == 2 | ||||
demo_check_info(info, requires_dist={"package"}) | ||||
@pytest.mark.skipif(not PY35, reason="Parsing of setup.cfg is skipped for Python | ||||
< 3.5") | ||||
def test_info_setup_cfg(mocker, demo_setup_cfg): | ||||
spy = mocker.spy(VirtualEnv, "run") | spy = mocker.spy(VirtualEnv, "run") | |||
info = PackageInfo.from_directory(demo_setup_cfg) | info = PackageInfo.from_directory(demo_setup_cfg) | |||
assert spy.call_count == 0 | assert spy.call_count == 0 | |||
demo_check_info(info, requires_dist={"package"}) | demo_check_info(info, requires_dist={"package"}) | |||
def test_info_setup_complex(demo_setup_complex): | def test_info_setup_complex(demo_setup_complex: Path): | |||
info = PackageInfo.from_directory(demo_setup_complex) | info = PackageInfo.from_directory(demo_setup_complex) | |||
demo_check_info(info, requires_dist={"package"}) | demo_check_info(info, requires_dist={"package"}) | |||
def test_info_setup_complex_pep517_error(mocker, demo_setup_complex): | def test_info_setup_complex_pep517_error( | |||
mocker: MockerFixture, demo_setup_complex: Path | ||||
): | ||||
mocker.patch( | mocker.patch( | |||
"poetry.utils.env.VirtualEnv.run", | "poetry.utils.env.VirtualEnv.run", | |||
autospec=True, | autospec=True, | |||
side_effect=EnvCommandError(CalledProcessError(1, "mock", output="mock") ), | side_effect=EnvCommandError(CalledProcessError(1, "mock", output="mock") ), | |||
) | ) | |||
with pytest.raises(PackageInfoError): | with pytest.raises(PackageInfoError): | |||
PackageInfo.from_directory(demo_setup_complex) | PackageInfo.from_directory(demo_setup_complex) | |||
def test_info_setup_complex_pep517_legacy(demo_setup_complex_pep517_legacy): | def test_info_setup_complex_pep517_legacy(demo_setup_complex_pep517_legacy: Path ): | |||
info = PackageInfo.from_directory(demo_setup_complex_pep517_legacy) | info = PackageInfo.from_directory(demo_setup_complex_pep517_legacy) | |||
demo_check_info(info, requires_dist={"package"}) | demo_check_info(info, requires_dist={"package"}) | |||
@pytest.mark.skipif(not PY35, reason="Parsing of setup.py is skipped for Python | def test_info_setup_complex_disable_build( | |||
< 3.5") | mocker: MockerFixture, demo_setup_complex: Path | |||
def test_info_setup_complex_disable_build(mocker, demo_setup_complex): | ): | |||
spy = mocker.spy(VirtualEnv, "run") | spy = mocker.spy(VirtualEnv, "run") | |||
info = PackageInfo.from_directory(demo_setup_complex, disable_build=True) | info = PackageInfo.from_directory(demo_setup_complex, disable_build=True) | |||
assert spy.call_count == 0 | assert spy.call_count == 0 | |||
assert info.name == "demo" | assert info.name == "demo" | |||
assert info.version == "0.1.0" | assert info.version == "0.1.0" | |||
assert info.requires_dist is None | assert info.requires_dist is None | |||
@pytest.mark.skipif(not PY35, reason="Parsing of setup.py is skipped for Python < 3.5") | ||||
@pytest.mark.parametrize("missing", ["version", "name", "install_requires"]) | @pytest.mark.parametrize("missing", ["version", "name", "install_requires"]) | |||
def test_info_setup_missing_mandatory_should_trigger_pep517( | def test_info_setup_missing_mandatory_should_trigger_pep517( | |||
mocker, source_dir, missing | mocker: MockerFixture, source_dir: Path, missing: str | |||
): | ): | |||
setup = "from setuptools import setup; " | setup = "from setuptools import setup; " | |||
setup += "setup(" | setup += "setup(" | |||
setup += 'name="demo", ' if missing != "name" else "" | setup += 'name="demo", ' if missing != "name" else "" | |||
setup += 'version="0.1.0", ' if missing != "version" else "" | setup += 'version="0.1.0", ' if missing != "version" else "" | |||
setup += 'install_requires=["package"]' if missing != "install_requires" els e "" | setup += 'install_requires=["package"]' if missing != "install_requires" els e "" | |||
setup += ")" | setup += ")" | |||
setup_py = source_dir / "setup.py" | setup_py = source_dir / "setup.py" | |||
setup_py.write_text(decode(setup)) | setup_py.write_text(decode(setup)) | |||
End of changes. 32 change blocks. | ||||
56 lines changed or deleted | 44 lines changed or added |