Commit 72497bcb by finswimmer Committed by GitHub

Add missing type hints & Force type hints - Part 3 (#4805)

* add typehints to tests.publishing

* add typehints to tests.puzzle

* add typehints to tests.repositories

* add typehints to tests.utils.test_authenticator, tests.utils.test_env, tests.utils.test_env_site, tests.utils.test_exporter

* add typehints to tests.utils.test_extras, tests.utils.test_helpers, tests.utils.test_password_manager, tests.utils.test_patterns, tests.utils.test_pip, tests.utils.setup_reader

* add typehints to tests.test_factory

* add typehints to tests.helpers

* add remaining missing typehints to tests.conftest

* add flake8-annotations to flake8 pre-commit hook

* create a FixtureDirGetter protocol type

* add comments to .flake8 settings and fix missing typehints after rebase
parent 1a3ecfb8
...@@ -3,6 +3,9 @@ min_python_version = 3.6.0 ...@@ -3,6 +3,9 @@ min_python_version = 3.6.0
max-line-length = 88 max-line-length = 88
ban-relative-imports = true ban-relative-imports = true
inline-quotes = double inline-quotes = double
# Allow omission of a return type hint for __init__ if at least one argument is annotated
# used by flake8-annotations
mypy-init-return = true
enable-extensions = TC, TC2 enable-extensions = TC, TC2
type-checking-exempt-modules = typing, typing-extensions type-checking-exempt-modules = typing, typing-extensions
extend-ignore = extend-ignore =
...@@ -12,10 +15,17 @@ extend-ignore = ...@@ -12,10 +15,17 @@ extend-ignore =
E203, E203,
# SIM106: Handle error-cases first # SIM106: Handle error-cases first
SIM106, SIM106,
# ANN101: Missing type annotation for self in method
ANN101,
# ANN102: Missing type annotation for cls in classmethod
ANN102,
per-file-ignores = per-file-ignores =
# F401: Module imported by unused (non-implicit modules) # F401: Module imported by unused (non-implicit modules)
# TC002: Move third-party import '...' into a type-checking block # TC002: Move third-party import '...' into a type-checking block
__init__.py:F401,TC002, __init__.py:F401,TC002,
# ANN201: Missing return type annotation for public function
tests/test_*:ANN201
tests/**/test_*:ANN201
extend-exclude = extend-exclude =
# Frozen and not subject to change in this repo: # Frozen and not subject to change in this repo:
get-poetry.py, get-poetry.py,
......
...@@ -31,6 +31,7 @@ repos: ...@@ -31,6 +31,7 @@ repos:
hooks: hooks:
- id: yesqa - id: yesqa
additional_dependencies: &flake8_deps additional_dependencies: &flake8_deps
- flake8-annotations==2.7.0
- flake8-broken-line==0.4.0 - flake8-broken-line==0.4.0
- flake8-bugbear==21.9.2 - flake8-bugbear==21.9.2
- flake8-comprehensions==3.7.0 - flake8-comprehensions==3.7.0
......
...@@ -187,7 +187,7 @@ class Executor: ...@@ -187,7 +187,7 @@ class Executor:
return 1 if self._shutdown else 0 return 1 if self._shutdown else 0
@staticmethod @staticmethod
def _get_max_workers(desired_max_workers: Optional[int] = None): def _get_max_workers(desired_max_workers: Optional[int] = None) -> int:
# This should be directly handled by ThreadPoolExecutor # This should be directly handled by ThreadPoolExecutor
# however, on some systems the number of CPUs cannot be determined # however, on some systems the number of CPUs cannot be determined
# (it raises a NotImplementedError), so, in this case, we assume # (it raises a NotImplementedError), so, in this case, we assume
......
...@@ -8,10 +8,11 @@ from contextlib import suppress ...@@ -8,10 +8,11 @@ from contextlib import suppress
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
from typing import Callable
from typing import Dict from typing import Dict
from typing import Iterator from typing import Iterator
from typing import List
from typing import Optional from typing import Optional
from typing import TextIO
from typing import Tuple from typing import Tuple
from typing import Type from typing import Type
...@@ -42,8 +43,15 @@ from tests.helpers import mock_download ...@@ -42,8 +43,15 @@ from tests.helpers import mock_download
if TYPE_CHECKING: if TYPE_CHECKING:
from pytest_mock import MockerFixture
from poetry.installation.executor import Executor
from poetry.poetry import Poetry from poetry.poetry import Poetry
from poetry.utils.env import Env
from poetry.utils.env import MockEnv
from tests.helpers import PoetryTestApplication
from tests.types import CommandTesterFactory from tests.types import CommandTesterFactory
from tests.types import FixtureDirGetter
from tests.types import ProjectFactory from tests.types import ProjectFactory
...@@ -68,41 +76,43 @@ class Config(BaseConfig): ...@@ -68,41 +76,43 @@ class Config(BaseConfig):
class DummyBackend(KeyringBackend): class DummyBackend(KeyringBackend):
def __init__(self): def __init__(self) -> None:
self._passwords = {} self._passwords = {}
@classmethod @classmethod
def priority(cls): def priority(cls) -> int:
return 42 return 42
def set_password(self, service, username, password): def set_password(
self, service: str, username: Optional[str], password: Any
) -> None:
self._passwords[service] = {username: password} self._passwords[service] = {username: password}
def get_password(self, service, username): def get_password(self, service: str, username: Optional[str]) -> Any:
return self._passwords.get(service, {}).get(username) return self._passwords.get(service, {}).get(username)
def get_credential(self, service, username): def get_credential(self, service: str, username: Optional[str]) -> Any:
return self._passwords.get(service, {}).get(username) return self._passwords.get(service, {}).get(username)
def delete_password(self, service, username): def delete_password(self, service: str, username: Optional[str]) -> None:
if service in self._passwords and username in self._passwords[service]: if service in self._passwords and username in self._passwords[service]:
del self._passwords[service][username] del self._passwords[service][username]
@pytest.fixture() @pytest.fixture()
def dummy_keyring(): def dummy_keyring() -> DummyBackend:
return DummyBackend() return DummyBackend()
@pytest.fixture() @pytest.fixture()
def with_simple_keyring(dummy_keyring): def with_simple_keyring(dummy_keyring: DummyBackend) -> None:
import keyring import keyring
keyring.set_keyring(dummy_keyring) keyring.set_keyring(dummy_keyring)
@pytest.fixture() @pytest.fixture()
def with_fail_keyring(): def with_fail_keyring() -> None:
import keyring import keyring
from keyring.backends.fail import Keyring from keyring.backends.fail import Keyring
...@@ -111,7 +121,7 @@ def with_fail_keyring(): ...@@ -111,7 +121,7 @@ def with_fail_keyring():
@pytest.fixture() @pytest.fixture()
def with_chained_keyring(mocker): def with_chained_keyring(mocker: "MockerFixture") -> None:
from keyring.backends.fail import Keyring from keyring.backends.fail import Keyring
mocker.patch("keyring.backend.get_all_keyring", [Keyring()]) mocker.patch("keyring.backend.get_all_keyring", [Keyring()])
...@@ -130,12 +140,12 @@ def config_cache_dir(tmp_dir: str) -> Path: ...@@ -130,12 +140,12 @@ def config_cache_dir(tmp_dir: str) -> Path:
@pytest.fixture @pytest.fixture
def config_virtualenvs_path(config_cache_dir): def config_virtualenvs_path(config_cache_dir: Path) -> Path:
return config_cache_dir / "virtualenvs" return config_cache_dir / "virtualenvs"
@pytest.fixture @pytest.fixture
def config_source(config_cache_dir): def config_source(config_cache_dir: Path) -> DictConfigSource:
source = DictConfigSource() source = DictConfigSource()
source.add_property("cache-dir", str(config_cache_dir)) source.add_property("cache-dir", str(config_cache_dir))
...@@ -150,7 +160,11 @@ def auth_config_source() -> DictConfigSource: ...@@ -150,7 +160,11 @@ def auth_config_source() -> DictConfigSource:
@pytest.fixture @pytest.fixture
def config(config_source, auth_config_source, mocker) -> Config: def config(
config_source: DictConfigSource,
auth_config_source: DictConfigSource,
mocker: "MockerFixture",
) -> Config:
import keyring import keyring
from keyring.backends.fail import Keyring from keyring.backends.fail import Keyring
...@@ -169,7 +183,7 @@ def config(config_source, auth_config_source, mocker) -> Config: ...@@ -169,7 +183,7 @@ def config(config_source, auth_config_source, mocker) -> Config:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_user_config_dir(mocker): def mock_user_config_dir(mocker: "MockerFixture") -> Iterator[None]:
config_dir = tempfile.mkdtemp(prefix="poetry_config_") config_dir = tempfile.mkdtemp(prefix="poetry_config_")
mocker.patch("poetry.locations.CONFIG_DIR", new=config_dir) mocker.patch("poetry.locations.CONFIG_DIR", new=config_dir)
mocker.patch("poetry.factory.CONFIG_DIR", new=config_dir) mocker.patch("poetry.factory.CONFIG_DIR", new=config_dir)
...@@ -178,7 +192,7 @@ def mock_user_config_dir(mocker): ...@@ -178,7 +192,7 @@ def mock_user_config_dir(mocker):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def download_mock(mocker): def download_mock(mocker: "MockerFixture") -> None:
# Patch download to not download anything but to just copy from fixtures # Patch download to not download anything but to just copy from fixtures
mocker.patch("poetry.utils.helpers.download_file", new=mock_download) mocker.patch("poetry.utils.helpers.download_file", new=mock_download)
mocker.patch("poetry.puzzle.provider.download_file", new=mock_download) mocker.patch("poetry.puzzle.provider.download_file", new=mock_download)
...@@ -186,9 +200,9 @@ def download_mock(mocker): ...@@ -186,9 +200,9 @@ def download_mock(mocker):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def pep517_metadata_mock(mocker): def pep517_metadata_mock(mocker: "MockerFixture") -> None:
@classmethod @classmethod
def _pep517_metadata(cls, path): def _pep517_metadata(cls: PackageInfo, path: Path) -> PackageInfo:
with suppress(PackageInfoError): with suppress(PackageInfoError):
return PackageInfo.from_setup_files(path) return PackageInfo.from_setup_files(path)
return PackageInfo(name="demo", version="0.1.2") return PackageInfo(name="demo", version="0.1.2")
...@@ -210,7 +224,7 @@ def environ() -> Iterator[None]: ...@@ -210,7 +224,7 @@ def environ() -> Iterator[None]:
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def git_mock(mocker): def git_mock(mocker: "MockerFixture") -> None:
# Patch git module to not actually clone projects # Patch git module to not actually clone projects
mocker.patch("poetry.core.vcs.git.Git.clone", new=mock_clone) mocker.patch("poetry.core.vcs.git.Git.clone", new=mock_clone)
mocker.patch("poetry.core.vcs.git.Git.checkout", new=lambda *_: None) mocker.patch("poetry.core.vcs.git.Git.checkout", new=lambda *_: None)
...@@ -235,8 +249,8 @@ def fixture_base() -> Path: ...@@ -235,8 +249,8 @@ def fixture_base() -> Path:
@pytest.fixture @pytest.fixture
def fixture_dir(fixture_base: Path) -> Callable[[str], Path]: def fixture_dir(fixture_base: Path) -> "FixtureDirGetter":
def _fixture_dir(name: str): def _fixture_dir(name: str) -> Path:
return fixture_base / name return fixture_base / name
return _fixture_dir return _fixture_dir
...@@ -252,18 +266,18 @@ def tmp_dir() -> Iterator[str]: ...@@ -252,18 +266,18 @@ def tmp_dir() -> Iterator[str]:
@pytest.fixture @pytest.fixture
def mocked_open_files(mocker): def mocked_open_files(mocker: "MockerFixture") -> List:
files = [] files = []
original = Path.open original = Path.open
def mocked_open(self, *args, **kwargs): def mocked_open(self: Path, *args: Any, **kwargs: Any) -> TextIO:
if self.name in {"pyproject.toml"}: if self.name in {"pyproject.toml"}:
return mocker.MagicMock() return mocker.MagicMock()
return original(self, *args, **kwargs) return original(self, *args, **kwargs)
mocker.patch("pathlib.Path.open", mocked_open) mocker.patch("pathlib.Path.open", mocked_open)
yield files return files
@pytest.fixture @pytest.fixture
...@@ -376,8 +390,16 @@ def project_factory( ...@@ -376,8 +390,16 @@ def project_factory(
@pytest.fixture @pytest.fixture
def command_tester_factory(app, env) -> "CommandTesterFactory": def command_tester_factory(
def _tester(command, poetry=None, installer=None, executor=None, environment=None): app: "PoetryTestApplication", env: "MockEnv"
) -> "CommandTesterFactory":
def _tester(
command: str,
poetry: Optional["Poetry"] = None,
installer: Optional[Installer] = None,
executor: Optional["Executor"] = None,
environment: Optional["Env"] = None,
) -> CommandTester:
command = app.find(command) command = app.find(command)
tester = CommandTester(command) tester = CommandTester(command)
......
...@@ -2,7 +2,6 @@ import json ...@@ -2,7 +2,6 @@ import json
import os import os
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Callable
import pytest import pytest
...@@ -20,6 +19,7 @@ if TYPE_CHECKING: ...@@ -20,6 +19,7 @@ if TYPE_CHECKING:
from poetry.config.dict_config_source import DictConfigSource from poetry.config.dict_config_source import DictConfigSource
from tests.conftest import Config from tests.conftest import Config
from tests.types import CommandTesterFactory from tests.types import CommandTesterFactory
from tests.types import FixtureDirGetter
@pytest.fixture() @pytest.fixture()
...@@ -98,7 +98,7 @@ def test_display_single_setting(tester: "CommandTester", config: "Config"): ...@@ -98,7 +98,7 @@ def test_display_single_setting(tester: "CommandTester", config: "Config"):
def test_display_single_local_setting( def test_display_single_local_setting(
command_tester_factory: "CommandTesterFactory", fixture_dir: Callable[[str], "Path"] command_tester_factory: "CommandTesterFactory", fixture_dir: "FixtureDirGetter"
): ):
tester = command_tester_factory( tester = command_tester_factory(
"config", poetry=Factory().create_poetry(fixture_dir("with_local_config")) "config", poetry=Factory().create_poetry(fixture_dir("with_local_config"))
......
...@@ -4,7 +4,6 @@ import sys ...@@ -4,7 +4,6 @@ import sys
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Callable
from typing import Iterator from typing import Iterator
import pytest import pytest
...@@ -22,6 +21,7 @@ if TYPE_CHECKING: ...@@ -22,6 +21,7 @@ if TYPE_CHECKING:
from poetry.poetry import Poetry from poetry.poetry import Poetry
from tests.helpers import TestRepository from tests.helpers import TestRepository
from tests.types import FixtureDirGetter
@pytest.fixture @pytest.fixture
...@@ -339,7 +339,7 @@ def test_interactive_with_directory_dependency( ...@@ -339,7 +339,7 @@ def test_interactive_with_directory_dependency(
tester: CommandTester, tester: CommandTester,
repo: "TestRepository", repo: "TestRepository",
source_dir: Path, source_dir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
repo.add_package(get_package("pendulum", "2.0.0")) repo.add_package(get_package("pendulum", "2.0.0"))
repo.add_package(get_package("pytest", "3.6.0")) repo.add_package(get_package("pytest", "3.6.0"))
...@@ -390,7 +390,7 @@ def test_interactive_with_directory_dependency_and_other_name( ...@@ -390,7 +390,7 @@ def test_interactive_with_directory_dependency_and_other_name(
tester: CommandTester, tester: CommandTester,
repo: "TestRepository", repo: "TestRepository",
source_dir: Path, source_dir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
repo.add_package(get_package("pendulum", "2.0.0")) repo.add_package(get_package("pendulum", "2.0.0"))
repo.add_package(get_package("pytest", "3.6.0")) repo.add_package(get_package("pytest", "3.6.0"))
...@@ -442,7 +442,7 @@ def test_interactive_with_file_dependency( ...@@ -442,7 +442,7 @@ def test_interactive_with_file_dependency(
tester: CommandTester, tester: CommandTester,
repo: "TestRepository", repo: "TestRepository",
source_dir: Path, source_dir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
repo.add_package(get_package("pendulum", "2.0.0")) repo.add_package(get_package("pendulum", "2.0.0"))
repo.add_package(get_package("pytest", "3.6.0")) repo.add_package(get_package("pytest", "3.6.0"))
......
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Callable
from typing import Type from typing import Type
import pytest import pytest
...@@ -17,6 +16,7 @@ if TYPE_CHECKING: ...@@ -17,6 +16,7 @@ if TYPE_CHECKING:
from poetry.poetry import Poetry from poetry.poetry import Poetry
from tests.helpers import TestRepository from tests.helpers import TestRepository
from tests.types import CommandTesterFactory from tests.types import CommandTesterFactory
from tests.types import FixtureDirGetter
from tests.types import ProjectFactory from tests.types import ProjectFactory
...@@ -33,7 +33,7 @@ def tester(command_tester_factory: "CommandTesterFactory") -> "CommandTester": ...@@ -33,7 +33,7 @@ def tester(command_tester_factory: "CommandTesterFactory") -> "CommandTester":
def _project_factory( def _project_factory(
fixture_name: str, fixture_name: str,
project_factory: "ProjectFactory", project_factory: "ProjectFactory",
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
) -> "Poetry": ) -> "Poetry":
source = fixture_dir(fixture_name) source = fixture_dir(fixture_name)
pyproject_content = (source / "pyproject.toml").read_text(encoding="utf-8") pyproject_content = (source / "pyproject.toml").read_text(encoding="utf-8")
...@@ -47,21 +47,21 @@ def _project_factory( ...@@ -47,21 +47,21 @@ def _project_factory(
@pytest.fixture @pytest.fixture
def poetry_with_outdated_lockfile( def poetry_with_outdated_lockfile(
project_factory: "ProjectFactory", fixture_dir: Callable[[str], Path] project_factory: "ProjectFactory", fixture_dir: "FixtureDirGetter"
) -> "Poetry": ) -> "Poetry":
return _project_factory("outdated_lock", project_factory, fixture_dir) return _project_factory("outdated_lock", project_factory, fixture_dir)
@pytest.fixture @pytest.fixture
def poetry_with_up_to_date_lockfile( def poetry_with_up_to_date_lockfile(
project_factory: "ProjectFactory", fixture_dir: Callable[[str], Path] project_factory: "ProjectFactory", fixture_dir: "FixtureDirGetter"
) -> "Poetry": ) -> "Poetry":
return _project_factory("up_to_date_lock", project_factory, fixture_dir) return _project_factory("up_to_date_lock", project_factory, fixture_dir)
@pytest.fixture @pytest.fixture
def poetry_with_old_lockfile( def poetry_with_old_lockfile(
project_factory: "ProjectFactory", fixture_dir: Callable[[str], Path] project_factory: "ProjectFactory", fixture_dir: "FixtureDirGetter"
) -> "Poetry": ) -> "Poetry":
return _project_factory("old_lock", project_factory, fixture_dir) return _project_factory("old_lock", project_factory, fixture_dir)
......
...@@ -3,6 +3,12 @@ import shutil ...@@ -3,6 +3,12 @@ import shutil
import urllib.parse import urllib.parse
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Union
from poetry.console.application import Application from poetry.console.application import Application
from poetry.core.masonry.utils.helpers import escape_name from poetry.core.masonry.utils.helpers import escape_name
...@@ -19,16 +25,29 @@ from poetry.repositories.exceptions import PackageNotFound ...@@ -19,16 +25,29 @@ from poetry.repositories.exceptions import PackageNotFound
from poetry.utils._compat import WINDOWS from poetry.utils._compat import WINDOWS
if TYPE_CHECKING:
from tomlkit.toml_document import TOMLDocument
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.types import DependencyTypes
from poetry.core.semver.version import Version
from poetry.installation.operations import OperationTypes
from poetry.poetry import Poetry
FIXTURE_PATH = Path(__file__).parent / "fixtures" FIXTURE_PATH = Path(__file__).parent / "fixtures"
def get_package(name, version): def get_package(name: str, version: Union[str, "Version"]) -> Package:
return Package(name, version) return Package(name, version)
def get_dependency( def get_dependency(
name, constraint=None, groups=None, optional=False, allows_prereleases=False name: str,
): constraint: Optional[Union[str, Dict[str, Any]]] = None,
groups: Optional[List[str]] = None,
optional: bool = False,
allows_prereleases: bool = False,
) -> "DependencyTypes":
if constraint is None: if constraint is None:
constraint = "*" constraint = "*"
...@@ -41,14 +60,14 @@ def get_dependency( ...@@ -41,14 +60,14 @@ def get_dependency(
return Factory.create_dependency(name, constraint or "*", groups=groups) return Factory.create_dependency(name, constraint or "*", groups=groups)
def fixture(path=None): def fixture(path: Optional[str] = None) -> Path:
if path: if path:
return FIXTURE_PATH / path return FIXTURE_PATH / path
else: else:
return FIXTURE_PATH return FIXTURE_PATH
def copy_or_symlink(source, dest): def copy_or_symlink(source: Path, dest: Path) -> None:
if dest.exists(): if dest.exists():
if dest.is_symlink(): if dest.is_symlink():
os.unlink(str(dest)) os.unlink(str(dest))
...@@ -72,7 +91,7 @@ def copy_or_symlink(source, dest): ...@@ -72,7 +91,7 @@ def copy_or_symlink(source, dest):
os.symlink(str(source), str(dest)) os.symlink(str(source), str(dest))
def mock_clone(_, source, dest): def mock_clone(_: Any, source: str, dest: Path) -> None:
# Checking source to determine which folder we need to copy # Checking source to determine which folder we need to copy
parsed = ParsedUrl.parse(source) parsed = ParsedUrl.parse(source)
...@@ -87,7 +106,7 @@ def mock_clone(_, source, dest): ...@@ -87,7 +106,7 @@ def mock_clone(_, source, dest):
copy_or_symlink(folder, dest) copy_or_symlink(folder, dest)
def mock_download(url, dest, **__): def mock_download(url: str, dest: str, **__: Any) -> None:
parts = urllib.parse.urlparse(url) parts = urllib.parse.urlparse(url)
fixtures = Path(__file__).parent / "fixtures" fixtures = Path(__file__).parent / "fixtures"
...@@ -97,7 +116,7 @@ def mock_download(url, dest, **__): ...@@ -97,7 +116,7 @@ def mock_download(url, dest, **__):
class TestExecutor(Executor): class TestExecutor(Executor):
def __init__(self, *args, **kwargs): def __init__(self, *args: Any, **kwargs: Any):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._installs = [] self._installs = []
...@@ -105,39 +124,39 @@ class TestExecutor(Executor): ...@@ -105,39 +124,39 @@ class TestExecutor(Executor):
self._uninstalls = [] self._uninstalls = []
@property @property
def installations(self): def installations(self) -> List[Package]:
return self._installs return self._installs
@property @property
def updates(self): def updates(self) -> List[Package]:
return self._updates return self._updates
@property @property
def removals(self): def removals(self) -> List[Package]:
return self._uninstalls return self._uninstalls
def _do_execute_operation(self, operation): def _do_execute_operation(self, operation: "OperationTypes") -> None:
super()._do_execute_operation(operation) super()._do_execute_operation(operation)
if not operation.skipped: if not operation.skipped:
getattr(self, f"_{operation.job_type}s").append(operation.package) getattr(self, f"_{operation.job_type}s").append(operation.package)
def _execute_install(self, operation): def _execute_install(self, operation: "OperationTypes") -> int:
return 0 return 0
def _execute_update(self, operation): def _execute_update(self, operation: "OperationTypes") -> int:
return 0 return 0
def _execute_remove(self, operation): def _execute_remove(self, operation: "OperationTypes") -> int:
return 0 return 0
class PoetryTestApplication(Application): class PoetryTestApplication(Application):
def __init__(self, poetry): def __init__(self, poetry: "Poetry"):
super().__init__() super().__init__()
self._poetry = poetry self._poetry = poetry
def reset_poetry(self): def reset_poetry(self) -> None:
poetry = self._poetry poetry = self._poetry
self._poetry = Factory().create_poetry(self._poetry.file.path.parent) self._poetry = Factory().create_poetry(self._poetry.file.path.parent)
self._poetry.set_pool(poetry.pool) self._poetry.set_pool(poetry.pool)
...@@ -148,7 +167,7 @@ class PoetryTestApplication(Application): ...@@ -148,7 +167,7 @@ class PoetryTestApplication(Application):
class TestLocker(Locker): class TestLocker(Locker):
def __init__(self, lock, local_config): def __init__(self, lock: Union[str, Path], local_config: Dict):
self._lock = TOMLFile(lock) self._lock = TOMLFile(lock)
self._local_config = local_config self._local_config = local_config
self._lock_data = None self._lock_data = None
...@@ -157,26 +176,26 @@ class TestLocker(Locker): ...@@ -157,26 +176,26 @@ class TestLocker(Locker):
self._lock_data = None self._lock_data = None
self._write = False self._write = False
def write(self, write=True): def write(self, write: bool = True) -> None:
self._write = write self._write = write
def is_locked(self): def is_locked(self) -> bool:
return self._locked return self._locked
def locked(self, is_locked=True): def locked(self, is_locked: bool = True) -> "TestLocker":
self._locked = is_locked self._locked = is_locked
return self return self
def mock_lock_data(self, data): def mock_lock_data(self, data: Dict) -> None:
self.locked() self.locked()
self._lock_data = data self._lock_data = data
def is_fresh(self): def is_fresh(self) -> bool:
return True return True
def _write_lock_data(self, data): def _write_lock_data(self, data: "TOMLDocument") -> None:
if self._write: if self._write:
super()._write_lock_data(data) super()._write_lock_data(data)
self._locked = True self._locked = True
...@@ -186,14 +205,14 @@ class TestLocker(Locker): ...@@ -186,14 +205,14 @@ class TestLocker(Locker):
class TestRepository(Repository): class TestRepository(Repository):
def find_packages(self, dependency): def find_packages(self, dependency: "Dependency") -> List[Package]:
packages = super().find_packages(dependency) packages = super().find_packages(dependency)
if len(packages) == 0: if len(packages) == 0:
raise PackageNotFound(f"Package [{dependency.name}] not found.") raise PackageNotFound(f"Package [{dependency.name}] not found.")
return packages return packages
def find_links_for_package(self, package): def find_links_for_package(self, package: Package) -> List[Link]:
return [ return [
Link( Link(
"https://foo.bar/files/{}-{}-py2.py3-none-any.whl".format( "https://foo.bar/files/{}-{}-py2.py3-none-any.whl".format(
......
...@@ -5,7 +5,6 @@ import shutil ...@@ -5,7 +5,6 @@ import shutil
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
from typing import Callable
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
...@@ -37,6 +36,7 @@ if TYPE_CHECKING: ...@@ -37,6 +36,7 @@ if TYPE_CHECKING:
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from poetry.utils.env import VirtualEnv from poetry.utils.env import VirtualEnv
from tests.types import FixtureDirGetter
@pytest.fixture @pytest.fixture
...@@ -531,7 +531,7 @@ def test_executor_should_use_cached_link_and_hash( ...@@ -531,7 +531,7 @@ def test_executor_should_use_cached_link_and_hash(
config: Config, config: Config,
io: BufferedIO, io: BufferedIO,
mocker: "MockerFixture", mocker: "MockerFixture",
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
# Produce a file:/// URI that is a valid link # Produce a file:/// URI that is a valid link
link_cached = Link( link_cached = Link(
...@@ -573,15 +573,15 @@ def test_executor_should_use_cached_link_and_hash( ...@@ -573,15 +573,15 @@ def test_executor_should_use_cached_link_and_hash(
], ],
) )
def test_executor_should_be_initialized_with_correct_workers( def test_executor_should_be_initialized_with_correct_workers(
tmp_venv, tmp_venv: "VirtualEnv",
pool, pool: Pool,
config, config: Config,
io, io: BufferedIO,
mocker, mocker: "MockerFixture",
max_workers, max_workers: Optional[int],
cpu_count, cpu_count: Optional[int],
side_effect, side_effect: Optional[Exception],
expected_workers, expected_workers: int,
): ):
config = Config() config = Config()
config.merge({"installer": {"max-workers": max_workers}}) config.merge({"installer": {"max-workers": max_workers}})
......
...@@ -4,7 +4,6 @@ import json ...@@ -4,7 +4,6 @@ import json
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
from typing import Callable
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
...@@ -49,6 +48,7 @@ if TYPE_CHECKING: ...@@ -49,6 +48,7 @@ if TYPE_CHECKING:
from poetry.packages import DependencyPackage from poetry.packages import DependencyPackage
from poetry.utils.env import Env from poetry.utils.env import Env
from tests.conftest import Config from tests.conftest import Config
from tests.types import FixtureDirGetter
RESERVED_PACKAGES = ("pip", "setuptools", "wheel") RESERVED_PACKAGES = ("pip", "setuptools", "wheel")
...@@ -1195,7 +1195,7 @@ def test_run_installs_with_local_file( ...@@ -1195,7 +1195,7 @@ def test_run_installs_with_local_file(
locker: Locker, locker: Locker,
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl") file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl")
package.add_dependency(Factory.create_dependency("demo", {"file": str(file_path)})) package.add_dependency(Factory.create_dependency("demo", {"file": str(file_path)}))
...@@ -1215,7 +1215,7 @@ def test_run_installs_wheel_with_no_requires_dist( ...@@ -1215,7 +1215,7 @@ def test_run_installs_wheel_with_no_requires_dist(
locker: Locker, locker: Locker,
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir( file_path = fixture_dir(
"wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.whl" "wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.whl"
...@@ -1237,7 +1237,7 @@ def test_run_installs_with_local_poetry_directory_and_extras( ...@@ -1237,7 +1237,7 @@ def test_run_installs_with_local_poetry_directory_and_extras(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: Path, tmpdir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir("project_with_extras") file_path = fixture_dir("project_with_extras")
package.add_dependency( package.add_dependency(
...@@ -1262,7 +1262,7 @@ def test_run_installs_with_local_poetry_directory_transitive( ...@@ -1262,7 +1262,7 @@ def test_run_installs_with_local_poetry_directory_transitive(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: Path, tmpdir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
root_dir = fixture_dir("directory") root_dir = fixture_dir("directory")
package.root_dir = root_dir package.root_dir = root_dir
...@@ -1294,7 +1294,7 @@ def test_run_installs_with_local_poetry_file_transitive( ...@@ -1294,7 +1294,7 @@ def test_run_installs_with_local_poetry_file_transitive(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: str, tmpdir: str,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
root_dir = fixture_dir("directory") root_dir = fixture_dir("directory")
package.root_dir = root_dir package.root_dir = root_dir
...@@ -1328,7 +1328,7 @@ def test_run_installs_with_local_setuptools_directory( ...@@ -1328,7 +1328,7 @@ def test_run_installs_with_local_setuptools_directory(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: Path, tmpdir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir("project_with_setup/") file_path = fixture_dir("project_with_setup/")
package.add_dependency( package.add_dependency(
......
...@@ -2,7 +2,6 @@ import itertools ...@@ -2,7 +2,6 @@ import itertools
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Callable
from typing import Dict from typing import Dict
from typing import Optional from typing import Optional
from typing import Tuple from typing import Tuple
...@@ -37,6 +36,7 @@ if TYPE_CHECKING: ...@@ -37,6 +36,7 @@ if TYPE_CHECKING:
from poetry.utils.env import Env from poetry.utils.env import Env
from tests.conftest import Config from tests.conftest import Config
from tests.types import FixtureDirGetter
RESERVED_PACKAGES = ("pip", "setuptools", "wheel") RESERVED_PACKAGES = ("pip", "setuptools", "wheel")
...@@ -842,7 +842,7 @@ def test_run_installs_with_local_file( ...@@ -842,7 +842,7 @@ def test_run_installs_with_local_file(
locker: Locker, locker: Locker,
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl") file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl")
package.add_dependency(Factory.create_dependency("demo", {"file": str(file_path)})) package.add_dependency(Factory.create_dependency("demo", {"file": str(file_path)}))
...@@ -863,7 +863,7 @@ def test_run_installs_wheel_with_no_requires_dist( ...@@ -863,7 +863,7 @@ def test_run_installs_wheel_with_no_requires_dist(
locker: Locker, locker: Locker,
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir( file_path = fixture_dir(
"wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.whl" "wheel_with_no_requires_dist/demo-0.1.0-py2.py3-none-any.whl"
...@@ -885,7 +885,7 @@ def test_run_installs_with_local_poetry_directory_and_extras( ...@@ -885,7 +885,7 @@ def test_run_installs_with_local_poetry_directory_and_extras(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: Path, tmpdir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir("project_with_extras") file_path = fixture_dir("project_with_extras")
package.add_dependency( package.add_dependency(
...@@ -911,7 +911,7 @@ def test_run_installs_with_local_poetry_directory_transitive( ...@@ -911,7 +911,7 @@ def test_run_installs_with_local_poetry_directory_transitive(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: Path, tmpdir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
root_dir = fixture_dir("directory") root_dir = fixture_dir("directory")
package.root_dir = root_dir package.root_dir = root_dir
...@@ -943,7 +943,7 @@ def test_run_installs_with_local_poetry_file_transitive( ...@@ -943,7 +943,7 @@ def test_run_installs_with_local_poetry_file_transitive(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: Path, tmpdir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
root_dir = fixture_dir("directory") root_dir = fixture_dir("directory")
package.root_dir = root_dir package.root_dir = root_dir
...@@ -975,7 +975,7 @@ def test_run_installs_with_local_setuptools_directory( ...@@ -975,7 +975,7 @@ def test_run_installs_with_local_setuptools_directory(
repo: Repository, repo: Repository,
package: ProjectPackage, package: ProjectPackage,
tmpdir: Path, tmpdir: Path,
fixture_dir: Callable[[str], Path], fixture_dir: "FixtureDirGetter",
): ):
file_path = fixture_dir("project_with_setup/") file_path = fixture_dir("project_with_setup/")
package.add_dependency( package.add_dependency(
......
import os import os
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
import pytest import pytest
...@@ -11,7 +12,16 @@ from poetry.factory import Factory ...@@ -11,7 +12,16 @@ from poetry.factory import Factory
from poetry.publishing.publisher import Publisher from poetry.publishing.publisher import Publisher
def test_publish_publishes_to_pypi_by_default(fixture_dir, mocker, config): if TYPE_CHECKING:
from pytest_mock import MockerFixture
from tests.conftest import Config
from tests.types import FixtureDirGetter
def test_publish_publishes_to_pypi_by_default(
fixture_dir: "FixtureDirGetter", mocker: "MockerFixture", config: "Config"
):
uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth") uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload") uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload")
poetry = Factory().create_poetry(fixture_dir("sample_project")) poetry = Factory().create_poetry(fixture_dir("sample_project"))
...@@ -30,11 +40,12 @@ def test_publish_publishes_to_pypi_by_default(fixture_dir, mocker, config): ...@@ -30,11 +40,12 @@ def test_publish_publishes_to_pypi_by_default(fixture_dir, mocker, config):
] == uploader_upload.call_args ] == uploader_upload.call_args
@pytest.mark.parametrize( @pytest.mark.parametrize("fixture_name", ["sample_project", "with_default_source"])
("fixture_name",), [("sample_project",), ("with_default_source",)]
)
def test_publish_can_publish_to_given_repository( def test_publish_can_publish_to_given_repository(
fixture_dir, mocker, config, fixture_name fixture_dir: "FixtureDirGetter",
mocker: "MockerFixture",
config: "Config",
fixture_name: str,
): ):
uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth") uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload") uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload")
...@@ -62,7 +73,9 @@ def test_publish_can_publish_to_given_repository( ...@@ -62,7 +73,9 @@ def test_publish_can_publish_to_given_repository(
assert "Publishing my-package (1.2.3) to foo" in io.fetch_output() assert "Publishing my-package (1.2.3) to foo" in io.fetch_output()
def test_publish_raises_error_for_undefined_repository(fixture_dir, mocker, config): def test_publish_raises_error_for_undefined_repository(
fixture_dir: "FixtureDirGetter", config: "Config"
):
poetry = Factory().create_poetry(fixture_dir("sample_project")) poetry = Factory().create_poetry(fixture_dir("sample_project"))
poetry._config = config poetry._config = config
poetry.config.merge( poetry.config.merge(
...@@ -74,7 +87,9 @@ def test_publish_raises_error_for_undefined_repository(fixture_dir, mocker, conf ...@@ -74,7 +87,9 @@ def test_publish_raises_error_for_undefined_repository(fixture_dir, mocker, conf
publisher.publish("my-repo", None, None) publisher.publish("my-repo", None, None)
def test_publish_uses_token_if_it_exists(fixture_dir, mocker, config): def test_publish_uses_token_if_it_exists(
fixture_dir: "FixtureDirGetter", mocker: "MockerFixture", config: "Config"
):
uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth") uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload") uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload")
poetry = Factory().create_poetry(fixture_dir("sample_project")) poetry = Factory().create_poetry(fixture_dir("sample_project"))
...@@ -91,7 +106,9 @@ def test_publish_uses_token_if_it_exists(fixture_dir, mocker, config): ...@@ -91,7 +106,9 @@ def test_publish_uses_token_if_it_exists(fixture_dir, mocker, config):
] == uploader_upload.call_args ] == uploader_upload.call_args
def test_publish_uses_cert(fixture_dir, mocker, config): def test_publish_uses_cert(
fixture_dir: "FixtureDirGetter", mocker: "MockerFixture", config: "Config"
):
cert = "path/to/ca.pem" cert = "path/to/ca.pem"
uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth") uploader_auth = mocker.patch("poetry.publishing.uploader.Uploader.auth")
uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload") uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload")
...@@ -115,7 +132,9 @@ def test_publish_uses_cert(fixture_dir, mocker, config): ...@@ -115,7 +132,9 @@ def test_publish_uses_cert(fixture_dir, mocker, config):
] == uploader_upload.call_args ] == uploader_upload.call_args
def test_publish_uses_client_cert(fixture_dir, mocker, config): def test_publish_uses_client_cert(
fixture_dir: "FixtureDirGetter", mocker: "MockerFixture", config: "Config"
):
client_cert = "path/to/client.pem" client_cert = "path/to/client.pem"
uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload") uploader_upload = mocker.patch("poetry.publishing.uploader.Uploader.upload")
poetry = Factory().create_poetry(fixture_dir("sample_project")) poetry = Factory().create_poetry(fixture_dir("sample_project"))
...@@ -136,7 +155,12 @@ def test_publish_uses_client_cert(fixture_dir, mocker, config): ...@@ -136,7 +155,12 @@ def test_publish_uses_client_cert(fixture_dir, mocker, config):
] == uploader_upload.call_args ] == uploader_upload.call_args
def test_publish_read_from_environment_variable(fixture_dir, environ, mocker, config): def test_publish_read_from_environment_variable(
fixture_dir: "FixtureDirGetter",
environ: None,
mocker: "MockerFixture",
config: "Config",
):
os.environ["POETRY_REPOSITORIES_FOO_URL"] = "https://foo.bar" os.environ["POETRY_REPOSITORIES_FOO_URL"] = "https://foo.bar"
os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar" os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar"
os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz" os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz"
......
from pathlib import Path from typing import TYPE_CHECKING
from typing import Type
import pytest import pytest
...@@ -9,19 +10,22 @@ from poetry.publishing.uploader import Uploader ...@@ -9,19 +10,22 @@ from poetry.publishing.uploader import Uploader
from poetry.publishing.uploader import UploadError from poetry.publishing.uploader import UploadError
fixtures_dir = Path(__file__).parent.parent / "fixtures" if TYPE_CHECKING:
import httpretty
from pytest_mock import MockerFixture
def project(name): from tests.types import FixtureDirGetter
return fixtures_dir / name
@pytest.fixture @pytest.fixture
def uploader(): def uploader(fixture_dir: "FixtureDirGetter") -> Uploader:
return Uploader(Factory().create_poetry(project("simple_project")), NullIO()) return Uploader(Factory().create_poetry(fixture_dir("simple_project")), NullIO())
def test_uploader_properly_handles_400_errors(http, uploader): def test_uploader_properly_handles_400_errors(
http: Type["httpretty.httpretty"], uploader: Uploader
):
http.register_uri(http.POST, "https://foo.com", status=400, body="Bad request") http.register_uri(http.POST, "https://foo.com", status=400, body="Bad request")
with pytest.raises(UploadError) as e: with pytest.raises(UploadError) as e:
...@@ -30,7 +34,9 @@ def test_uploader_properly_handles_400_errors(http, uploader): ...@@ -30,7 +34,9 @@ def test_uploader_properly_handles_400_errors(http, uploader):
assert str(e.value) == "HTTP Error 400: Bad Request" assert str(e.value) == "HTTP Error 400: Bad Request"
def test_uploader_properly_handles_403_errors(http, uploader): def test_uploader_properly_handles_403_errors(
http: Type["httpretty.httpretty"], uploader: Uploader
):
http.register_uri(http.POST, "https://foo.com", status=403, body="Unauthorized") http.register_uri(http.POST, "https://foo.com", status=403, body="Unauthorized")
with pytest.raises(UploadError) as e: with pytest.raises(UploadError) as e:
...@@ -39,7 +45,9 @@ def test_uploader_properly_handles_403_errors(http, uploader): ...@@ -39,7 +45,9 @@ def test_uploader_properly_handles_403_errors(http, uploader):
assert str(e.value) == "HTTP Error 403: Forbidden" assert str(e.value) == "HTTP Error 403: Forbidden"
def test_uploader_properly_handles_301_redirects(http, uploader): def test_uploader_properly_handles_301_redirects(
http: Type["httpretty.httpretty"], uploader: Uploader
):
http.register_uri(http.POST, "https://foo.com", status=301, body="Redirect") http.register_uri(http.POST, "https://foo.com", status=301, body="Redirect")
with pytest.raises(UploadError) as e: with pytest.raises(UploadError) as e:
...@@ -51,7 +59,9 @@ def test_uploader_properly_handles_301_redirects(http, uploader): ...@@ -51,7 +59,9 @@ def test_uploader_properly_handles_301_redirects(http, uploader):
) )
def test_uploader_registers_for_appropriate_400_errors(mocker, http, uploader): def test_uploader_registers_for_appropriate_400_errors(
mocker: "MockerFixture", http: Type["httpretty.httpretty"], uploader: Uploader
):
register = mocker.patch("poetry.publishing.uploader.Uploader._register") register = mocker.patch("poetry.publishing.uploader.Uploader._register")
http.register_uri( http.register_uri(
http.POST, "https://foo.com", status=400, body="No package was ever registered" http.POST, "https://foo.com", status=400, body="No package was ever registered"
......
import shutil import shutil
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
import pytest import pytest
...@@ -10,8 +11,13 @@ try: ...@@ -10,8 +11,13 @@ try:
except ImportError: except ImportError:
import urlparse import urlparse
if TYPE_CHECKING:
from pytest_mock import MockerFixture
def mock_clone(self, source, dest): from poetry.core.vcs import Git
def mock_clone(self: "Git", source: str, dest: Path) -> None:
# Checking source to determine which folder we need to copy # Checking source to determine which folder we need to copy
parts = urlparse.urlparse(source) parts = urlparse.urlparse(source)
...@@ -28,11 +34,9 @@ def mock_clone(self, source, dest): ...@@ -28,11 +34,9 @@ def mock_clone(self, source, dest):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def setup(mocker): def setup(mocker: "MockerFixture") -> None:
# Patch git module to not actually clone projects # Patch git module to not actually clone projects
mocker.patch("poetry.core.vcs.git.Git.clone", new=mock_clone) mocker.patch("poetry.core.vcs.git.Git.clone", new=mock_clone)
mocker.patch("poetry.core.vcs.git.Git.checkout", new=lambda *_: None) mocker.patch("poetry.core.vcs.git.Git.checkout", new=lambda *_: None)
p = mocker.patch("poetry.core.vcs.git.Git.rev_parse") p = mocker.patch("poetry.core.vcs.git.Git.rev_parse")
p.return_value = "9cf87a285a2d3fbb0b9fa621997b3acc3631ed24" p.return_value = "9cf87a285a2d3fbb0b9fa621997b3acc3631ed24"
yield
from pathlib import Path from pathlib import Path
from subprocess import CalledProcessError from subprocess import CalledProcessError
from typing import TYPE_CHECKING
import pytest import pytest
...@@ -18,23 +19,27 @@ from poetry.utils.env import MockEnv as BaseMockEnv ...@@ -18,23 +19,27 @@ from poetry.utils.env import MockEnv as BaseMockEnv
from tests.helpers import get_dependency from tests.helpers import get_dependency
if TYPE_CHECKING:
from pytest_mock import MockerFixture
class MockEnv(BaseMockEnv): class MockEnv(BaseMockEnv):
def run(self, bin, *args): def run(self, bin: str, *args: str) -> None:
raise EnvCommandError(CalledProcessError(1, "python", output="")) raise EnvCommandError(CalledProcessError(1, "python", output=""))
@pytest.fixture @pytest.fixture
def root(): def root() -> ProjectPackage:
return ProjectPackage("root", "1.2.3") return ProjectPackage("root", "1.2.3")
@pytest.fixture @pytest.fixture
def repository(): def repository() -> Repository:
return Repository() return Repository()
@pytest.fixture @pytest.fixture
def pool(repository): def pool(repository: Repository) -> Pool:
pool = Pool() pool = Pool()
pool.add_repository(repository) pool.add_repository(repository)
...@@ -42,12 +47,12 @@ def pool(repository): ...@@ -42,12 +47,12 @@ def pool(repository):
@pytest.fixture @pytest.fixture
def provider(root, pool): def provider(root: ProjectPackage, pool: Pool) -> Provider:
return Provider(root, pool, NullIO()) return Provider(root, pool, NullIO())
@pytest.mark.parametrize("value", [True, False]) @pytest.mark.parametrize("value", [True, False])
def test_search_for_vcs_retains_develop_flag(provider, value): def test_search_for_vcs_retains_develop_flag(provider: Provider, value: bool):
dependency = VCSDependency( dependency = VCSDependency(
"demo", "git", "https://github.com/demo/demo.git", develop=value "demo", "git", "https://github.com/demo/demo.git", develop=value
) )
...@@ -55,7 +60,7 @@ def test_search_for_vcs_retains_develop_flag(provider, value): ...@@ -55,7 +60,7 @@ def test_search_for_vcs_retains_develop_flag(provider, value):
assert package.develop == value assert package.develop == value
def test_search_for_vcs_setup_egg_info(provider): def test_search_for_vcs_setup_egg_info(provider: Provider):
dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git") dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git")
package = provider.search_for_vcs(dependency)[0] package = provider.search_for_vcs(dependency)[0]
...@@ -73,7 +78,7 @@ def test_search_for_vcs_setup_egg_info(provider): ...@@ -73,7 +78,7 @@ def test_search_for_vcs_setup_egg_info(provider):
} }
def test_search_for_vcs_setup_egg_info_with_extras(provider): def test_search_for_vcs_setup_egg_info_with_extras(provider: Provider):
dependency = VCSDependency( dependency = VCSDependency(
"demo", "git", "https://github.com/demo/demo.git", extras=["foo"] "demo", "git", "https://github.com/demo/demo.git", extras=["foo"]
) )
...@@ -93,7 +98,7 @@ def test_search_for_vcs_setup_egg_info_with_extras(provider): ...@@ -93,7 +98,7 @@ def test_search_for_vcs_setup_egg_info_with_extras(provider):
} }
def test_search_for_vcs_read_setup(provider, mocker): def test_search_for_vcs_read_setup(provider: Provider, mocker: "MockerFixture"):
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv()) mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git") dependency = VCSDependency("demo", "git", "https://github.com/demo/demo.git")
...@@ -113,7 +118,9 @@ def test_search_for_vcs_read_setup(provider, mocker): ...@@ -113,7 +118,9 @@ def test_search_for_vcs_read_setup(provider, mocker):
} }
def test_search_for_vcs_read_setup_with_extras(provider, mocker): def test_search_for_vcs_read_setup_with_extras(
provider: Provider, mocker: "MockerFixture"
):
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv()) mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = VCSDependency( dependency = VCSDependency(
...@@ -131,7 +138,9 @@ def test_search_for_vcs_read_setup_with_extras(provider, mocker): ...@@ -131,7 +138,9 @@ def test_search_for_vcs_read_setup_with_extras(provider, mocker):
assert optional == [get_dependency("tomlkit"), get_dependency("cleo")] assert optional == [get_dependency("tomlkit"), get_dependency("cleo")]
def test_search_for_vcs_read_setup_raises_error_if_no_version(provider, mocker): def test_search_for_vcs_read_setup_raises_error_if_no_version(
provider: Provider, mocker: "MockerFixture"
):
mocker.patch( mocker.patch(
"poetry.inspection.info.PackageInfo._pep517_metadata", "poetry.inspection.info.PackageInfo._pep517_metadata",
return_value=PackageInfo(name="demo", version=None), return_value=PackageInfo(name="demo", version=None),
...@@ -144,7 +153,7 @@ def test_search_for_vcs_read_setup_raises_error_if_no_version(provider, mocker): ...@@ -144,7 +153,7 @@ def test_search_for_vcs_read_setup_raises_error_if_no_version(provider, mocker):
@pytest.mark.parametrize("directory", ["demo", "non-canonical-name"]) @pytest.mark.parametrize("directory", ["demo", "non-canonical-name"])
def test_search_for_directory_setup_egg_info(provider, directory): def test_search_for_directory_setup_egg_info(provider: Provider, directory: str):
dependency = DirectoryDependency( dependency = DirectoryDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -170,7 +179,7 @@ def test_search_for_directory_setup_egg_info(provider, directory): ...@@ -170,7 +179,7 @@ def test_search_for_directory_setup_egg_info(provider, directory):
} }
def test_search_for_directory_setup_egg_info_with_extras(provider): def test_search_for_directory_setup_egg_info_with_extras(provider: Provider):
dependency = DirectoryDependency( dependency = DirectoryDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -198,7 +207,7 @@ def test_search_for_directory_setup_egg_info_with_extras(provider): ...@@ -198,7 +207,7 @@ def test_search_for_directory_setup_egg_info_with_extras(provider):
@pytest.mark.parametrize("directory", ["demo", "non-canonical-name"]) @pytest.mark.parametrize("directory", ["demo", "non-canonical-name"])
def test_search_for_directory_setup_with_base(provider, directory): def test_search_for_directory_setup_with_base(provider: Provider, directory: str):
dependency = DirectoryDependency( dependency = DirectoryDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -238,7 +247,9 @@ def test_search_for_directory_setup_with_base(provider, directory): ...@@ -238,7 +247,9 @@ def test_search_for_directory_setup_with_base(provider, directory):
) )
def test_search_for_directory_setup_read_setup(provider, mocker): def test_search_for_directory_setup_read_setup(
provider: Provider, mocker: "MockerFixture"
):
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv()) mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = DirectoryDependency( dependency = DirectoryDependency(
...@@ -266,7 +277,9 @@ def test_search_for_directory_setup_read_setup(provider, mocker): ...@@ -266,7 +277,9 @@ def test_search_for_directory_setup_read_setup(provider, mocker):
} }
def test_search_for_directory_setup_read_setup_with_extras(provider, mocker): def test_search_for_directory_setup_read_setup_with_extras(
provider: Provider, mocker: "MockerFixture"
):
mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv()) mocker.patch("poetry.utils.env.EnvManager.get", return_value=MockEnv())
dependency = DirectoryDependency( dependency = DirectoryDependency(
...@@ -295,7 +308,7 @@ def test_search_for_directory_setup_read_setup_with_extras(provider, mocker): ...@@ -295,7 +308,7 @@ def test_search_for_directory_setup_read_setup_with_extras(provider, mocker):
} }
def test_search_for_directory_setup_read_setup_with_no_dependencies(provider): def test_search_for_directory_setup_read_setup_with_no_dependencies(provider: Provider):
dependency = DirectoryDependency( dependency = DirectoryDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -314,7 +327,7 @@ def test_search_for_directory_setup_read_setup_with_no_dependencies(provider): ...@@ -314,7 +327,7 @@ def test_search_for_directory_setup_read_setup_with_no_dependencies(provider):
assert package.extras == {} assert package.extras == {}
def test_search_for_directory_poetry(provider): def test_search_for_directory_poetry(provider: Provider):
dependency = DirectoryDependency( dependency = DirectoryDependency(
"project-with-extras", "project-with-extras",
Path(__file__).parent.parent / "fixtures" / "project_with_extras", Path(__file__).parent.parent / "fixtures" / "project_with_extras",
...@@ -342,7 +355,7 @@ def test_search_for_directory_poetry(provider): ...@@ -342,7 +355,7 @@ def test_search_for_directory_poetry(provider):
} }
def test_search_for_directory_poetry_with_extras(provider): def test_search_for_directory_poetry_with_extras(provider: Provider):
dependency = DirectoryDependency( dependency = DirectoryDependency(
"project-with-extras", "project-with-extras",
Path(__file__).parent.parent / "fixtures" / "project_with_extras", Path(__file__).parent.parent / "fixtures" / "project_with_extras",
...@@ -371,7 +384,7 @@ def test_search_for_directory_poetry_with_extras(provider): ...@@ -371,7 +384,7 @@ def test_search_for_directory_poetry_with_extras(provider):
} }
def test_search_for_file_sdist(provider): def test_search_for_file_sdist(provider: Provider):
dependency = FileDependency( dependency = FileDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -402,7 +415,7 @@ def test_search_for_file_sdist(provider): ...@@ -402,7 +415,7 @@ def test_search_for_file_sdist(provider):
} }
def test_search_for_file_sdist_with_extras(provider): def test_search_for_file_sdist_with_extras(provider: Provider):
dependency = FileDependency( dependency = FileDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -434,7 +447,7 @@ def test_search_for_file_sdist_with_extras(provider): ...@@ -434,7 +447,7 @@ def test_search_for_file_sdist_with_extras(provider):
} }
def test_search_for_file_wheel(provider): def test_search_for_file_wheel(provider: Provider):
dependency = FileDependency( dependency = FileDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -465,7 +478,7 @@ def test_search_for_file_wheel(provider): ...@@ -465,7 +478,7 @@ def test_search_for_file_wheel(provider):
} }
def test_search_for_file_wheel_with_extras(provider): def test_search_for_file_wheel_with_extras(provider: Provider):
dependency = FileDependency( dependency = FileDependency(
"demo", "demo",
Path(__file__).parent.parent Path(__file__).parent.parent
......
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Type
import pytest import pytest
...@@ -25,6 +31,12 @@ from tests.repositories.test_legacy_repository import ( ...@@ -25,6 +31,12 @@ from tests.repositories.test_legacy_repository import (
from tests.repositories.test_pypi_repository import MockRepository as MockPyPIRepository from tests.repositories.test_pypi_repository import MockRepository as MockPyPIRepository
if TYPE_CHECKING:
import httpretty
from poetry.installation.operations import OperationTypes
from poetry.puzzle.transaction import Transaction
DEFAULT_SOURCE_REF = ( DEFAULT_SOURCE_REF = (
VCSDependency("poetry", "git", "git@github.com:python-poetry/poetry.git").branch VCSDependency("poetry", "git", "git@github.com:python-poetry/poetry.git").branch
or "HEAD" or "HEAD"
...@@ -32,49 +44,59 @@ DEFAULT_SOURCE_REF = ( ...@@ -32,49 +44,59 @@ DEFAULT_SOURCE_REF = (
class Provider(BaseProvider): class Provider(BaseProvider):
def set_package_python_versions(self, python_versions): def set_package_python_versions(self, python_versions: str) -> None:
self._package.python_versions = python_versions self._package.python_versions = python_versions
self._python_constraint = self._package.python_constraint self._python_constraint = self._package.python_constraint
@pytest.fixture() @pytest.fixture()
def io(): def io() -> NullIO:
return NullIO() return NullIO()
@pytest.fixture() @pytest.fixture()
def package(): def package() -> ProjectPackage:
return ProjectPackage("root", "1.0") return ProjectPackage("root", "1.0")
@pytest.fixture() @pytest.fixture()
def installed(): def installed() -> InstalledRepository:
return InstalledRepository() return InstalledRepository()
@pytest.fixture() @pytest.fixture()
def locked(): def locked() -> Repository:
return Repository() return Repository()
@pytest.fixture() @pytest.fixture()
def repo(): def repo() -> Repository:
return Repository() return Repository()
@pytest.fixture() @pytest.fixture()
def pool(repo): def pool(repo: Repository) -> Pool:
return Pool([repo]) return Pool([repo])
@pytest.fixture() @pytest.fixture()
def solver(package, pool, installed, locked, io): def solver(
package: ProjectPackage,
pool: Pool,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
) -> Solver:
return Solver( return Solver(
package, pool, installed, locked, io, provider=Provider(package, pool, io) package, pool, installed, locked, io, provider=Provider(package, pool, io)
) )
def check_solver_result(transaction, expected, synchronize=False): def check_solver_result(
transaction: "Transaction",
expected: List[Dict[str, Any]],
synchronize: bool = False,
) -> List["OperationTypes"]:
for e in expected: for e in expected:
if "skipped" not in e: if "skipped" not in e:
e["skipped"] = False e["skipped"] = False
...@@ -103,7 +125,9 @@ def check_solver_result(transaction, expected, synchronize=False): ...@@ -103,7 +125,9 @@ def check_solver_result(transaction, expected, synchronize=False):
return ops return ops
def test_solver_install_single(solver, repo, package): def test_solver_install_single(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -114,7 +138,9 @@ def test_solver_install_single(solver, repo, package): ...@@ -114,7 +138,9 @@ def test_solver_install_single(solver, repo, package):
check_solver_result(transaction, [{"job": "install", "package": package_a}]) check_solver_result(transaction, [{"job": "install", "package": package_a}])
def test_solver_remove_if_no_longer_locked(solver, locked, installed): def test_solver_remove_if_no_longer_locked(
solver: Solver, locked: Repository, installed: InstalledRepository
):
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
installed.add_package(package_a) installed.add_package(package_a)
locked.add_package(package_a) locked.add_package(package_a)
...@@ -124,7 +150,7 @@ def test_solver_remove_if_no_longer_locked(solver, locked, installed): ...@@ -124,7 +150,7 @@ def test_solver_remove_if_no_longer_locked(solver, locked, installed):
check_solver_result(transaction, [{"job": "remove", "package": package_a}]) check_solver_result(transaction, [{"job": "remove", "package": package_a}])
def test_remove_non_installed(solver, repo, locked): def test_remove_non_installed(solver: Solver, repo: Repository, locked: Repository):
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
locked.add_package(package_a) locked.add_package(package_a)
...@@ -137,7 +163,9 @@ def test_remove_non_installed(solver, repo, locked): ...@@ -137,7 +163,9 @@ def test_remove_non_installed(solver, repo, locked):
check_solver_result(transaction, []) check_solver_result(transaction, [])
def test_install_non_existing_package_fail(solver, repo, package): def test_install_non_existing_package_fail(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("B", "1")) package.add_dependency(Factory.create_dependency("B", "1"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -147,7 +175,7 @@ def test_install_non_existing_package_fail(solver, repo, package): ...@@ -147,7 +175,7 @@ def test_install_non_existing_package_fail(solver, repo, package):
solver.solve() solver.solve()
def test_solver_with_deps(solver, repo, package): def test_solver_with_deps(solver: Solver, repo: Repository, package: ProjectPackage):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -171,7 +199,9 @@ def test_solver_with_deps(solver, repo, package): ...@@ -171,7 +199,9 @@ def test_solver_with_deps(solver, repo, package):
) )
def test_install_honours_not_equal(solver, repo, package): def test_install_honours_not_equal(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -199,7 +229,9 @@ def test_install_honours_not_equal(solver, repo, package): ...@@ -199,7 +229,9 @@ def test_install_honours_not_equal(solver, repo, package):
) )
def test_install_with_deps_in_order(solver, repo, package): def test_install_with_deps_in_order(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
package.add_dependency(Factory.create_dependency("C", "*")) package.add_dependency(Factory.create_dependency("C", "*"))
...@@ -228,7 +260,12 @@ def test_install_with_deps_in_order(solver, repo, package): ...@@ -228,7 +260,12 @@ def test_install_with_deps_in_order(solver, repo, package):
) )
def test_install_installed(solver, repo, installed, package): def test_install_installed(
solver: Solver,
repo: Repository,
installed: InstalledRepository,
package: ProjectPackage,
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -242,7 +279,12 @@ def test_install_installed(solver, repo, installed, package): ...@@ -242,7 +279,12 @@ def test_install_installed(solver, repo, installed, package):
) )
def test_update_installed(solver, repo, installed, package): def test_update_installed(
solver: Solver,
repo: Repository,
installed: InstalledRepository,
package: ProjectPackage,
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
installed.add_package(get_package("A", "1.0")) installed.add_package(get_package("A", "1.0"))
...@@ -259,7 +301,13 @@ def test_update_installed(solver, repo, installed, package): ...@@ -259,7 +301,13 @@ def test_update_installed(solver, repo, installed, package):
) )
def test_update_with_use_latest(solver, repo, installed, package, locked): def test_update_with_use_latest(
solver: Solver,
repo: Repository,
installed: InstalledRepository,
package: ProjectPackage,
locked: Repository,
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
...@@ -288,7 +336,7 @@ def test_update_with_use_latest(solver, repo, installed, package, locked): ...@@ -288,7 +336,7 @@ def test_update_with_use_latest(solver, repo, installed, package, locked):
) )
def test_solver_sets_groups(solver, repo, package): def test_solver_sets_groups(solver: Solver, repo: Repository, package: ProjectPackage):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*", groups=["dev"])) package.add_dependency(Factory.create_dependency("B", "*", groups=["dev"]))
...@@ -317,7 +365,9 @@ def test_solver_sets_groups(solver, repo, package): ...@@ -317,7 +365,9 @@ def test_solver_sets_groups(solver, repo, package):
assert ops[1].package.category == "main" assert ops[1].package.category == "main"
def test_solver_respects_root_package_python_versions(solver, repo, package): def test_solver_respects_root_package_python_versions(
solver: Solver, repo: Repository, package: ProjectPackage
):
solver.provider.set_package_python_versions("~3.4") solver.provider.set_package_python_versions("~3.4")
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
...@@ -348,7 +398,9 @@ def test_solver_respects_root_package_python_versions(solver, repo, package): ...@@ -348,7 +398,9 @@ def test_solver_respects_root_package_python_versions(solver, repo, package):
) )
def test_solver_fails_if_mismatch_root_python_versions(solver, repo, package): def test_solver_fails_if_mismatch_root_python_versions(
solver: Solver, repo: Repository, package: ProjectPackage
):
solver.provider.set_package_python_versions("^3.4") solver.provider.set_package_python_versions("^3.4")
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
...@@ -368,7 +420,9 @@ def test_solver_fails_if_mismatch_root_python_versions(solver, repo, package): ...@@ -368,7 +420,9 @@ def test_solver_fails_if_mismatch_root_python_versions(solver, repo, package):
solver.solve() solver.solve()
def test_solver_solves_optional_and_compatible_packages(solver, repo, package): def test_solver_solves_optional_and_compatible_packages(
solver: Solver, repo: Repository, package: ProjectPackage
):
solver.provider.set_package_python_versions("~3.4") solver.provider.set_package_python_versions("~3.4")
package.extras["foo"] = [get_dependency("B")] package.extras["foo"] = [get_dependency("B")]
package.add_dependency( package.add_dependency(
...@@ -401,7 +455,9 @@ def test_solver_solves_optional_and_compatible_packages(solver, repo, package): ...@@ -401,7 +455,9 @@ def test_solver_solves_optional_and_compatible_packages(solver, repo, package):
) )
def test_solver_does_not_return_extras_if_not_requested(solver, repo, package): def test_solver_does_not_return_extras_if_not_requested(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
...@@ -426,7 +482,9 @@ def test_solver_does_not_return_extras_if_not_requested(solver, repo, package): ...@@ -426,7 +482,9 @@ def test_solver_does_not_return_extras_if_not_requested(solver, repo, package):
) )
def test_solver_returns_extras_if_requested(solver, repo, package): def test_solver_returns_extras_if_requested(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency( package.add_dependency(
Factory.create_dependency("B", {"version": "*", "extras": ["foo"]}) Factory.create_dependency("B", {"version": "*", "extras": ["foo"]})
...@@ -460,8 +518,13 @@ def test_solver_returns_extras_if_requested(solver, repo, package): ...@@ -460,8 +518,13 @@ def test_solver_returns_extras_if_requested(solver, repo, package):
assert ops[0].package.marker.is_any() assert ops[0].package.marker.is_any()
@pytest.mark.parametrize(("enabled_extra",), [("one",), ("two",), (None,)]) @pytest.mark.parametrize("enabled_extra", ["one", "two", None])
def test_solver_returns_extras_only_requested(solver, repo, package, enabled_extra): def test_solver_returns_extras_only_requested(
solver: Solver,
repo: Repository,
package: ProjectPackage,
enabled_extra: Optional[bool],
):
extras = [enabled_extra] if enabled_extra is not None else [] extras = [enabled_extra] if enabled_extra is not None else []
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
...@@ -517,9 +580,12 @@ def test_solver_returns_extras_only_requested(solver, repo, package, enabled_ext ...@@ -517,9 +580,12 @@ def test_solver_returns_extras_only_requested(solver, repo, package, enabled_ext
assert ops[0].package.marker.is_any() assert ops[0].package.marker.is_any()
@pytest.mark.parametrize(("enabled_extra",), [("one",), ("two",), (None,)]) @pytest.mark.parametrize("enabled_extra", ["one", "two", None])
def test_solver_returns_extras_when_multiple_extras_use_same_dependency( def test_solver_returns_extras_when_multiple_extras_use_same_dependency(
solver, repo, package, enabled_extra solver: Solver,
repo: Repository,
package: ProjectPackage,
enabled_extra: Optional[bool],
): ):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
...@@ -563,9 +629,12 @@ def test_solver_returns_extras_when_multiple_extras_use_same_dependency( ...@@ -563,9 +629,12 @@ def test_solver_returns_extras_when_multiple_extras_use_same_dependency(
assert ops[0].package.marker.is_any() assert ops[0].package.marker.is_any()
@pytest.mark.parametrize(("enabled_extra",), [("one",), ("two",), (None,)]) @pytest.mark.parametrize("enabled_extra", ["one", "two", None])
def test_solver_returns_extras_only_requested_nested( def test_solver_returns_extras_only_requested_nested(
solver, repo, package, enabled_extra solver: Solver,
repo: Repository,
package: ProjectPackage,
enabled_extra: Optional[bool],
): ):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
...@@ -619,7 +688,9 @@ def test_solver_returns_extras_only_requested_nested( ...@@ -619,7 +688,9 @@ def test_solver_returns_extras_only_requested_nested(
assert ops[0].package.marker.is_any() assert ops[0].package.marker.is_any()
def test_solver_returns_prereleases_if_requested(solver, repo, package): def test_solver_returns_prereleases_if_requested(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
package.add_dependency( package.add_dependency(
...@@ -648,7 +719,9 @@ def test_solver_returns_prereleases_if_requested(solver, repo, package): ...@@ -648,7 +719,9 @@ def test_solver_returns_prereleases_if_requested(solver, repo, package):
) )
def test_solver_does_not_return_prereleases_if_not_requested(solver, repo, package): def test_solver_does_not_return_prereleases_if_not_requested(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
package.add_dependency(Factory.create_dependency("C", "*")) package.add_dependency(Factory.create_dependency("C", "*"))
...@@ -675,7 +748,9 @@ def test_solver_does_not_return_prereleases_if_not_requested(solver, repo, packa ...@@ -675,7 +748,9 @@ def test_solver_does_not_return_prereleases_if_not_requested(solver, repo, packa
) )
def test_solver_sub_dependencies_with_requirements(solver, repo, package): def test_solver_sub_dependencies_with_requirements(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
...@@ -711,7 +786,9 @@ def test_solver_sub_dependencies_with_requirements(solver, repo, package): ...@@ -711,7 +786,9 @@ def test_solver_sub_dependencies_with_requirements(solver, repo, package):
assert op.package.marker.is_any() assert op.package.marker.is_any()
def test_solver_sub_dependencies_with_requirements_complex(solver, repo, package): def test_solver_sub_dependencies_with_requirements_complex(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency( package.add_dependency(
Factory.create_dependency("A", {"version": "^1.0", "python": "<5.0"}) Factory.create_dependency("A", {"version": "^1.0", "python": "<5.0"})
) )
...@@ -769,7 +846,7 @@ def test_solver_sub_dependencies_with_requirements_complex(solver, repo, package ...@@ -769,7 +846,7 @@ def test_solver_sub_dependencies_with_requirements_complex(solver, repo, package
def test_solver_sub_dependencies_with_not_supported_python_version( def test_solver_sub_dependencies_with_not_supported_python_version(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("^3.5") solver.provider.set_package_python_versions("^3.5")
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
...@@ -791,7 +868,7 @@ def test_solver_sub_dependencies_with_not_supported_python_version( ...@@ -791,7 +868,7 @@ def test_solver_sub_dependencies_with_not_supported_python_version(
def test_solver_sub_dependencies_with_not_supported_python_version_transitive( def test_solver_sub_dependencies_with_not_supported_python_version_transitive(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("^3.4") solver.provider.set_package_python_versions("^3.4")
...@@ -835,7 +912,7 @@ def test_solver_sub_dependencies_with_not_supported_python_version_transitive( ...@@ -835,7 +912,7 @@ def test_solver_sub_dependencies_with_not_supported_python_version_transitive(
def test_solver_with_dependency_in_both_default_and_dev_dependencies( def test_solver_with_dependency_in_both_default_and_dev_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("^3.5") solver.provider.set_package_python_versions("^3.5")
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
...@@ -888,7 +965,7 @@ def test_solver_with_dependency_in_both_default_and_dev_dependencies( ...@@ -888,7 +965,7 @@ def test_solver_with_dependency_in_both_default_and_dev_dependencies(
def test_solver_with_dependency_in_both_main_and_dev_dependencies_with_one_more_dependent( def test_solver_with_dependency_in_both_main_and_dev_dependencies_with_one_more_dependent(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("E", "*")) package.add_dependency(Factory.create_dependency("E", "*"))
...@@ -947,7 +1024,9 @@ def test_solver_with_dependency_in_both_main_and_dev_dependencies_with_one_more_ ...@@ -947,7 +1024,9 @@ def test_solver_with_dependency_in_both_main_and_dev_dependencies_with_one_more_
assert e.category == "main" assert e.category == "main"
def test_solver_with_dependency_and_prerelease_sub_dependencies(solver, repo, package): def test_solver_with_dependency_and_prerelease_sub_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -972,7 +1051,9 @@ def test_solver_with_dependency_and_prerelease_sub_dependencies(solver, repo, pa ...@@ -972,7 +1051,9 @@ def test_solver_with_dependency_and_prerelease_sub_dependencies(solver, repo, pa
) )
def test_solver_circular_dependency(solver, repo, package): def test_solver_circular_dependency(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -1002,7 +1083,9 @@ def test_solver_circular_dependency(solver, repo, package): ...@@ -1002,7 +1083,9 @@ def test_solver_circular_dependency(solver, repo, package):
assert ops[0].package.category == "main" assert ops[0].package.category == "main"
def test_solver_circular_dependency_chain(solver, repo, package): def test_solver_circular_dependency_chain(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -1037,7 +1120,9 @@ def test_solver_circular_dependency_chain(solver, repo, package): ...@@ -1037,7 +1120,9 @@ def test_solver_circular_dependency_chain(solver, repo, package):
assert ops[0].package.category == "main" assert ops[0].package.category == "main"
def test_solver_dense_dependencies(solver, repo, package): def test_solver_dense_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
# The root package depends on packages A0...An-1, # The root package depends on packages A0...An-1,
# And package Ai depends on packages A0...Ai-1 # And package Ai depends on packages A0...Ai-1
# This graph is a transitive tournament # This graph is a transitive tournament
...@@ -1058,7 +1143,9 @@ def test_solver_dense_dependencies(solver, repo, package): ...@@ -1058,7 +1143,9 @@ def test_solver_dense_dependencies(solver, repo, package):
) )
def test_solver_duplicate_dependencies_same_constraint(solver, repo, package): def test_solver_duplicate_dependencies_same_constraint(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -1085,7 +1172,9 @@ def test_solver_duplicate_dependencies_same_constraint(solver, repo, package): ...@@ -1085,7 +1172,9 @@ def test_solver_duplicate_dependencies_same_constraint(solver, repo, package):
) )
def test_solver_duplicate_dependencies_different_constraints(solver, repo, package): def test_solver_duplicate_dependencies_different_constraints(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -1116,7 +1205,7 @@ def test_solver_duplicate_dependencies_different_constraints(solver, repo, packa ...@@ -1116,7 +1205,7 @@ def test_solver_duplicate_dependencies_different_constraints(solver, repo, packa
def test_solver_duplicate_dependencies_different_constraints_same_requirements( def test_solver_duplicate_dependencies_different_constraints_same_requirements(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
...@@ -1143,7 +1232,7 @@ So, because no versions of a match !=1.0 ...@@ -1143,7 +1232,7 @@ So, because no versions of a match !=1.0
def test_solver_duplicate_dependencies_different_constraints_merge_no_markers( def test_solver_duplicate_dependencies_different_constraints_merge_no_markers(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "1.0")) package.add_dependency(Factory.create_dependency("B", "1.0"))
...@@ -1185,7 +1274,9 @@ def test_solver_duplicate_dependencies_different_constraints_merge_no_markers( ...@@ -1185,7 +1274,9 @@ def test_solver_duplicate_dependencies_different_constraints_merge_no_markers(
) )
def test_solver_duplicate_dependencies_sub_dependencies(solver, repo, package): def test_solver_duplicate_dependencies_sub_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
...@@ -1224,7 +1315,9 @@ def test_solver_duplicate_dependencies_sub_dependencies(solver, repo, package): ...@@ -1224,7 +1315,9 @@ def test_solver_duplicate_dependencies_sub_dependencies(solver, repo, package):
) )
def test_solver_fails_if_dependency_name_does_not_match_package(solver, repo, package): def test_solver_fails_if_dependency_name_does_not_match_package(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency( package.add_dependency(
Factory.create_dependency( Factory.create_dependency(
"my-demo", {"git": "https://github.com/demo/demo.git"} "my-demo", {"git": "https://github.com/demo/demo.git"}
...@@ -1236,7 +1329,7 @@ def test_solver_fails_if_dependency_name_does_not_match_package(solver, repo, pa ...@@ -1236,7 +1329,7 @@ def test_solver_fails_if_dependency_name_does_not_match_package(solver, repo, pa
def test_solver_does_not_get_stuck_in_recursion_on_circular_dependency( def test_solver_does_not_get_stuck_in_recursion_on_circular_dependency(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
package_a.add_dependency(Factory.create_dependency("B", "^1.0")) package_a.add_dependency(Factory.create_dependency("B", "^1.0"))
...@@ -1263,7 +1356,9 @@ def test_solver_does_not_get_stuck_in_recursion_on_circular_dependency( ...@@ -1263,7 +1356,9 @@ def test_solver_does_not_get_stuck_in_recursion_on_circular_dependency(
) )
def test_solver_can_resolve_git_dependencies(solver, repo, package): def test_solver_can_resolve_git_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1296,7 +1391,9 @@ def test_solver_can_resolve_git_dependencies(solver, repo, package): ...@@ -1296,7 +1391,9 @@ def test_solver_can_resolve_git_dependencies(solver, repo, package):
assert op.package.source_resolved_reference.startswith("9cf87a2") assert op.package.source_resolved_reference.startswith("9cf87a2")
def test_solver_can_resolve_git_dependencies_with_extras(solver, repo, package): def test_solver_can_resolve_git_dependencies_with_extras(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1334,7 +1431,9 @@ def test_solver_can_resolve_git_dependencies_with_extras(solver, repo, package): ...@@ -1334,7 +1431,9 @@ def test_solver_can_resolve_git_dependencies_with_extras(solver, repo, package):
[{"branch": "a-branch"}, {"tag": "a-tag"}, {"rev": "9cf8"}], [{"branch": "a-branch"}, {"tag": "a-tag"}, {"rev": "9cf8"}],
ids=["branch", "tag", "rev"], ids=["branch", "tag", "rev"],
) )
def test_solver_can_resolve_git_dependencies_with_ref(solver, repo, package, ref): def test_solver_can_resolve_git_dependencies_with_ref(
solver: Solver, repo: Repository, package: Package, ref: Dict[str, str]
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1368,7 +1467,7 @@ def test_solver_can_resolve_git_dependencies_with_ref(solver, repo, package, ref ...@@ -1368,7 +1467,7 @@ def test_solver_can_resolve_git_dependencies_with_ref(solver, repo, package, ref
def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requirement_is_compatible( def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requirement_is_compatible(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.4") solver.provider.set_package_python_versions("~2.7 || ^3.4")
package.add_dependency( package.add_dependency(
...@@ -1386,7 +1485,7 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir ...@@ -1386,7 +1485,7 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir
def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requirement_is_compatible_multiple( def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requirement_is_compatible_multiple(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.4") solver.provider.set_package_python_versions("~2.7 || ^3.4")
package.add_dependency( package.add_dependency(
...@@ -1418,7 +1517,7 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir ...@@ -1418,7 +1517,7 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir
def test_solver_triggers_conflict_for_dependency_python_not_fully_compatible_with_package_python( def test_solver_triggers_conflict_for_dependency_python_not_fully_compatible_with_package_python(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.4") solver.provider.set_package_python_versions("~2.7 || ^3.4")
package.add_dependency( package.add_dependency(
...@@ -1435,7 +1534,7 @@ def test_solver_triggers_conflict_for_dependency_python_not_fully_compatible_wit ...@@ -1435,7 +1534,7 @@ def test_solver_triggers_conflict_for_dependency_python_not_fully_compatible_wit
def test_solver_finds_compatible_package_for_dependency_python_not_fully_compatible_with_package_python( def test_solver_finds_compatible_package_for_dependency_python_not_fully_compatible_with_package_python(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.4") solver.provider.set_package_python_versions("~2.7 || ^3.4")
package.add_dependency( package.add_dependency(
...@@ -1457,7 +1556,7 @@ def test_solver_finds_compatible_package_for_dependency_python_not_fully_compati ...@@ -1457,7 +1556,7 @@ def test_solver_finds_compatible_package_for_dependency_python_not_fully_compati
def test_solver_does_not_trigger_new_resolution_on_duplicate_dependencies_if_only_extras( def test_solver_does_not_trigger_new_resolution_on_duplicate_dependencies_if_only_extras(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
dep1 = Dependency.create_from_pep_508('B (>=1.0); extra == "foo"') dep1 = Dependency.create_from_pep_508('B (>=1.0); extra == "foo"')
dep1.activate() dep1.activate()
...@@ -1495,7 +1594,7 @@ def test_solver_does_not_trigger_new_resolution_on_duplicate_dependencies_if_onl ...@@ -1495,7 +1594,7 @@ def test_solver_does_not_trigger_new_resolution_on_duplicate_dependencies_if_onl
def test_solver_does_not_raise_conflict_for_locked_conditional_dependencies( def test_solver_does_not_raise_conflict_for_locked_conditional_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.4") solver.provider.set_package_python_versions("~2.7 || ^3.4")
package.add_dependency( package.add_dependency(
...@@ -1527,7 +1626,7 @@ def test_solver_does_not_raise_conflict_for_locked_conditional_dependencies( ...@@ -1527,7 +1626,7 @@ def test_solver_does_not_raise_conflict_for_locked_conditional_dependencies(
def test_solver_returns_extras_if_requested_in_dependencies_and_not_in_root_package( def test_solver_returns_extras_if_requested_in_dependencies_and_not_in_root_package(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.add_dependency(Factory.create_dependency("A", "*")) package.add_dependency(Factory.create_dependency("A", "*"))
package.add_dependency(Factory.create_dependency("B", "*")) package.add_dependency(Factory.create_dependency("B", "*"))
...@@ -1566,7 +1665,7 @@ def test_solver_returns_extras_if_requested_in_dependencies_and_not_in_root_pack ...@@ -1566,7 +1665,7 @@ def test_solver_returns_extras_if_requested_in_dependencies_and_not_in_root_pack
def test_solver_should_not_resolve_prerelease_version_if_not_requested( def test_solver_should_not_resolve_prerelease_version_if_not_requested(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.add_dependency(Factory.create_dependency("A", "~1.8.0")) package.add_dependency(Factory.create_dependency("A", "~1.8.0"))
package.add_dependency(Factory.create_dependency("B", "^0.5.0")) package.add_dependency(Factory.create_dependency("B", "^0.5.0"))
...@@ -1585,7 +1684,7 @@ def test_solver_should_not_resolve_prerelease_version_if_not_requested( ...@@ -1585,7 +1684,7 @@ def test_solver_should_not_resolve_prerelease_version_if_not_requested(
def test_solver_ignores_dependencies_with_incompatible_python_full_version_marker( def test_solver_ignores_dependencies_with_incompatible_python_full_version_marker(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("^3.6") solver.provider.set_package_python_versions("^3.6")
package.add_dependency(Factory.create_dependency("A", "^1.0")) package.add_dependency(Factory.create_dependency("A", "^1.0"))
...@@ -1616,7 +1715,9 @@ def test_solver_ignores_dependencies_with_incompatible_python_full_version_marke ...@@ -1616,7 +1715,9 @@ def test_solver_ignores_dependencies_with_incompatible_python_full_version_marke
) )
def test_solver_git_dependencies_update(solver, repo, package, installed): def test_solver_git_dependencies_update(
solver: Solver, repo: Repository, package: Package, installed: InstalledRepository
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1663,7 +1764,9 @@ def test_solver_git_dependencies_update(solver, repo, package, installed): ...@@ -1663,7 +1764,9 @@ def test_solver_git_dependencies_update(solver, repo, package, installed):
assert op.initial_package.source_resolved_reference == "123456" assert op.initial_package.source_resolved_reference == "123456"
def test_solver_git_dependencies_update_skipped(solver, repo, package, installed): def test_solver_git_dependencies_update_skipped(
solver: Solver, repo: Repository, package: Package, installed: InstalledRepository
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1695,7 +1798,7 @@ def test_solver_git_dependencies_update_skipped(solver, repo, package, installed ...@@ -1695,7 +1798,7 @@ def test_solver_git_dependencies_update_skipped(solver, repo, package, installed
def test_solver_git_dependencies_short_hash_update_skipped( def test_solver_git_dependencies_short_hash_update_skipped(
solver, repo, package, installed solver: Solver, repo: Repository, package: Package, installed: InstalledRepository
): ):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
...@@ -1740,7 +1843,9 @@ def test_solver_git_dependencies_short_hash_update_skipped( ...@@ -1740,7 +1843,9 @@ def test_solver_git_dependencies_short_hash_update_skipped(
) )
def test_solver_can_resolve_directory_dependencies(solver, repo, package): def test_solver_can_resolve_directory_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1773,7 +1878,12 @@ def test_solver_can_resolve_directory_dependencies(solver, repo, package): ...@@ -1773,7 +1878,12 @@ def test_solver_can_resolve_directory_dependencies(solver, repo, package):
def test_solver_can_resolve_directory_dependencies_nested_editable( def test_solver_can_resolve_directory_dependencies_nested_editable(
solver, repo, pool, installed, locked, io solver: Solver,
repo: Repository,
pool: Pool,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
base = Path(__file__).parent.parent / "fixtures" / "project_with_nested_local" base = Path(__file__).parent.parent / "fixtures" / "project_with_nested_local"
poetry = Factory().create_poetry(cwd=base) poetry = Factory().create_poetry(cwd=base)
...@@ -1826,7 +1936,9 @@ def test_solver_can_resolve_directory_dependencies_nested_editable( ...@@ -1826,7 +1936,9 @@ def test_solver_can_resolve_directory_dependencies_nested_editable(
assert op.package.develop is True assert op.package.develop is True
def test_solver_can_resolve_directory_dependencies_with_extras(solver, repo, package): def test_solver_can_resolve_directory_dependencies_with_extras(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1866,7 +1978,9 @@ def test_solver_can_resolve_directory_dependencies_with_extras(solver, repo, pac ...@@ -1866,7 +1978,9 @@ def test_solver_can_resolve_directory_dependencies_with_extras(solver, repo, pac
assert op.package.source_url == path assert op.package.source_url == path
def test_solver_can_resolve_sdist_dependencies(solver, repo, package): def test_solver_can_resolve_sdist_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1896,7 +2010,9 @@ def test_solver_can_resolve_sdist_dependencies(solver, repo, package): ...@@ -1896,7 +2010,9 @@ def test_solver_can_resolve_sdist_dependencies(solver, repo, package):
assert op.package.source_url == path assert op.package.source_url == path
def test_solver_can_resolve_sdist_dependencies_with_extras(solver, repo, package): def test_solver_can_resolve_sdist_dependencies_with_extras(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1934,7 +2050,9 @@ def test_solver_can_resolve_sdist_dependencies_with_extras(solver, repo, package ...@@ -1934,7 +2050,9 @@ def test_solver_can_resolve_sdist_dependencies_with_extras(solver, repo, package
assert op.package.source_url == path assert op.package.source_url == path
def test_solver_can_resolve_wheel_dependencies(solver, repo, package): def test_solver_can_resolve_wheel_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -1964,7 +2082,9 @@ def test_solver_can_resolve_wheel_dependencies(solver, repo, package): ...@@ -1964,7 +2082,9 @@ def test_solver_can_resolve_wheel_dependencies(solver, repo, package):
assert op.package.source_url == path assert op.package.source_url == path
def test_solver_can_resolve_wheel_dependencies_with_extras(solver, repo, package): def test_solver_can_resolve_wheel_dependencies_with_extras(
solver: Solver, repo: Repository, package: ProjectPackage
):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
cleo = get_package("cleo", "1.0.0") cleo = get_package("cleo", "1.0.0")
repo.add_package(pendulum) repo.add_package(pendulum)
...@@ -2003,7 +2123,10 @@ def test_solver_can_resolve_wheel_dependencies_with_extras(solver, repo, package ...@@ -2003,7 +2123,10 @@ def test_solver_can_resolve_wheel_dependencies_with_extras(solver, repo, package
def test_solver_can_solve_with_legacy_repository_using_proper_dists( def test_solver_can_solve_with_legacy_repository_using_proper_dists(
package, installed, locked, io package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
repo = MockLegacyRepository() repo = MockLegacyRepository()
pool = Pool([repo]) pool = Pool([repo])
...@@ -2045,7 +2168,10 @@ def test_solver_can_solve_with_legacy_repository_using_proper_dists( ...@@ -2045,7 +2168,10 @@ def test_solver_can_solve_with_legacy_repository_using_proper_dists(
def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_dists( def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_dists(
package, installed, locked, io package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
package.python_versions = "^3.7" package.python_versions = "^3.7"
...@@ -2075,7 +2201,12 @@ def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_ ...@@ -2075,7 +2201,12 @@ def test_solver_can_solve_with_legacy_repository_using_proper_python_compatible_
) )
def test_solver_skips_invalid_versions(package, installed, locked, io): def test_solver_skips_invalid_versions(
package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
):
package.python_versions = "^3.7" package.python_versions = "^3.7"
repo = MockPyPIRepository() repo = MockPyPIRepository()
...@@ -2092,7 +2223,9 @@ def test_solver_skips_invalid_versions(package, installed, locked, io): ...@@ -2092,7 +2223,9 @@ def test_solver_skips_invalid_versions(package, installed, locked, io):
) )
def test_multiple_constraints_on_root(package, solver, repo): def test_multiple_constraints_on_root(
package: ProjectPackage, solver: Solver, repo: Repository
):
package.add_dependency( package.add_dependency(
Factory.create_dependency("foo", {"version": "^1.0", "python": "^2.7"}) Factory.create_dependency("foo", {"version": "^1.0", "python": "^2.7"})
) )
...@@ -2115,7 +2248,10 @@ def test_multiple_constraints_on_root(package, solver, repo): ...@@ -2115,7 +2248,10 @@ def test_multiple_constraints_on_root(package, solver, repo):
def test_solver_chooses_most_recent_version_amongst_repositories( def test_solver_chooses_most_recent_version_amongst_repositories(
package, installed, locked, io package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
package.python_versions = "^3.7" package.python_versions = "^3.7"
package.add_dependency(Factory.create_dependency("tomlkit", {"version": "^0.5"})) package.add_dependency(Factory.create_dependency("tomlkit", {"version": "^0.5"}))
...@@ -2136,7 +2272,10 @@ def test_solver_chooses_most_recent_version_amongst_repositories( ...@@ -2136,7 +2272,10 @@ def test_solver_chooses_most_recent_version_amongst_repositories(
def test_solver_chooses_from_correct_repository_if_forced( def test_solver_chooses_from_correct_repository_if_forced(
package, installed, locked, io package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
package.python_versions = "^3.7" package.python_versions = "^3.7"
package.add_dependency( package.add_dependency(
...@@ -2170,7 +2309,10 @@ def test_solver_chooses_from_correct_repository_if_forced( ...@@ -2170,7 +2309,10 @@ def test_solver_chooses_from_correct_repository_if_forced(
def test_solver_chooses_from_correct_repository_if_forced_and_transitive_dependency( def test_solver_chooses_from_correct_repository_if_forced_and_transitive_dependency(
package, installed, locked, io package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
package.python_versions = "^3.7" package.python_versions = "^3.7"
package.add_dependency(Factory.create_dependency("foo", "^1.0")) package.add_dependency(Factory.create_dependency("foo", "^1.0"))
...@@ -2212,7 +2354,10 @@ def test_solver_chooses_from_correct_repository_if_forced_and_transitive_depende ...@@ -2212,7 +2354,10 @@ def test_solver_chooses_from_correct_repository_if_forced_and_transitive_depende
def test_solver_does_not_choose_from_secondary_repository_by_default( def test_solver_does_not_choose_from_secondary_repository_by_default(
package, installed, locked, io package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
package.python_versions = "^3.7" package.python_versions = "^3.7"
package.add_dependency(Factory.create_dependency("clikit", {"version": "^0.2.0"})) package.add_dependency(Factory.create_dependency("clikit", {"version": "^0.2.0"}))
...@@ -2258,7 +2403,12 @@ def test_solver_does_not_choose_from_secondary_repository_by_default( ...@@ -2258,7 +2403,12 @@ def test_solver_does_not_choose_from_secondary_repository_by_default(
assert ops[2].package.source_url == "http://legacy.foo.bar" assert ops[2].package.source_url == "http://legacy.foo.bar"
def test_solver_chooses_from_secondary_if_explicit(package, installed, locked, io): def test_solver_chooses_from_secondary_if_explicit(
package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
):
package.python_versions = "^3.7" package.python_versions = "^3.7"
package.add_dependency( package.add_dependency(
Factory.create_dependency("clikit", {"version": "^0.2.0", "source": "PyPI"}) Factory.create_dependency("clikit", {"version": "^0.2.0", "source": "PyPI"})
...@@ -2298,7 +2448,12 @@ def test_solver_chooses_from_secondary_if_explicit(package, installed, locked, i ...@@ -2298,7 +2448,12 @@ def test_solver_chooses_from_secondary_if_explicit(package, installed, locked, i
def test_solver_discards_packages_with_empty_markers( def test_solver_discards_packages_with_empty_markers(
package, installed, locked, io, pool, repo package: ProjectPackage,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
pool: Pool,
repo: Repository,
): ):
package.python_versions = "~2.7 || ^3.4" package.python_versions = "~2.7 || ^3.4"
package.add_dependency( package.add_dependency(
...@@ -2334,7 +2489,7 @@ def test_solver_discards_packages_with_empty_markers( ...@@ -2334,7 +2489,7 @@ def test_solver_discards_packages_with_empty_markers(
def test_solver_does_not_raise_conflict_for_conditional_dev_dependencies( def test_solver_does_not_raise_conflict_for_conditional_dev_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.5") solver.provider.set_package_python_versions("~2.7 || ^3.5")
package.add_dependency( package.add_dependency(
...@@ -2366,7 +2521,7 @@ def test_solver_does_not_raise_conflict_for_conditional_dev_dependencies( ...@@ -2366,7 +2521,7 @@ def test_solver_does_not_raise_conflict_for_conditional_dev_dependencies(
def test_solver_does_not_loop_indefinitely_on_duplicate_constraints_with_extras( def test_solver_does_not_loop_indefinitely_on_duplicate_constraints_with_extras(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.5") solver.provider.set_package_python_versions("~2.7 || ^3.5")
package.add_dependency( package.add_dependency(
...@@ -2397,7 +2552,13 @@ def test_solver_does_not_loop_indefinitely_on_duplicate_constraints_with_extras( ...@@ -2397,7 +2552,13 @@ def test_solver_does_not_loop_indefinitely_on_duplicate_constraints_with_extras(
def test_solver_does_not_fail_with_locked_git_and_non_git_dependencies( def test_solver_does_not_fail_with_locked_git_and_non_git_dependencies(
solver, repo, package, locked, pool, installed, io solver: Solver,
repo: Repository,
package: Package,
locked: Repository,
pool: Pool,
installed: InstalledRepository,
io: NullIO,
): ):
package.add_dependency( package.add_dependency(
Factory.create_dependency("demo", {"git": "https://github.com/demo/demo.git"}) Factory.create_dependency("demo", {"git": "https://github.com/demo/demo.git"})
...@@ -2434,7 +2595,9 @@ def test_solver_does_not_fail_with_locked_git_and_non_git_dependencies( ...@@ -2434,7 +2595,9 @@ def test_solver_does_not_fail_with_locked_git_and_non_git_dependencies(
) )
def test_ignore_python_constraint_no_overlap_dependencies(solver, repo, package): def test_ignore_python_constraint_no_overlap_dependencies(
solver: Solver, repo: Repository, package: ProjectPackage
):
pytest = get_package("demo", "1.0.0") pytest = get_package("demo", "1.0.0")
pytest.add_dependency( pytest.add_dependency(
Factory.create_dependency( Factory.create_dependency(
...@@ -2458,7 +2621,7 @@ def test_ignore_python_constraint_no_overlap_dependencies(solver, repo, package) ...@@ -2458,7 +2621,7 @@ def test_ignore_python_constraint_no_overlap_dependencies(solver, repo, package)
def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies( def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.5") solver.provider.set_package_python_versions("~2.7 || ^3.5")
package.add_dependency(Factory.create_dependency("A", "^1.0")) package.add_dependency(Factory.create_dependency("A", "^1.0"))
...@@ -2490,7 +2653,13 @@ def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies( ...@@ -2490,7 +2653,13 @@ def test_solver_should_not_go_into_an_infinite_loop_on_duplicate_dependencies(
) )
def test_solver_synchronize_single(package, pool, installed, locked, io): def test_solver_synchronize_single(
package: ProjectPackage,
pool: Pool,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
):
solver = Solver(package, pool, installed, locked, io) solver = Solver(package, pool, installed, locked, io)
package_a = get_package("a", "1.0") package_a = get_package("a", "1.0")
installed.add_package(package_a) installed.add_package(package_a)
...@@ -2504,7 +2673,11 @@ def test_solver_synchronize_single(package, pool, installed, locked, io): ...@@ -2504,7 +2673,11 @@ def test_solver_synchronize_single(package, pool, installed, locked, io):
@pytest.mark.skip(reason="Poetry no longer has critical package requirements") @pytest.mark.skip(reason="Poetry no longer has critical package requirements")
def test_solver_with_synchronization_keeps_critical_package( def test_solver_with_synchronization_keeps_critical_package(
package, pool, installed, locked, io package: ProjectPackage,
pool: Pool,
installed: InstalledRepository,
locked: Repository,
io: NullIO,
): ):
solver = Solver(package, pool, installed, locked, io) solver = Solver(package, pool, installed, locked, io)
package_pip = get_package("setuptools", "1.0") package_pip = get_package("setuptools", "1.0")
...@@ -2516,7 +2689,7 @@ def test_solver_with_synchronization_keeps_critical_package( ...@@ -2516,7 +2689,7 @@ def test_solver_with_synchronization_keeps_critical_package(
def test_solver_cannot_choose_another_version_for_directory_dependencies( def test_solver_cannot_choose_another_version_for_directory_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
demo = get_package("demo", "0.1.0") demo = get_package("demo", "0.1.0")
...@@ -2545,7 +2718,7 @@ def test_solver_cannot_choose_another_version_for_directory_dependencies( ...@@ -2545,7 +2718,7 @@ def test_solver_cannot_choose_another_version_for_directory_dependencies(
def test_solver_cannot_choose_another_version_for_file_dependencies( def test_solver_cannot_choose_another_version_for_file_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
demo = get_package("demo", "0.0.8") demo = get_package("demo", "0.0.8")
...@@ -2572,7 +2745,7 @@ def test_solver_cannot_choose_another_version_for_file_dependencies( ...@@ -2572,7 +2745,7 @@ def test_solver_cannot_choose_another_version_for_file_dependencies(
def test_solver_cannot_choose_another_version_for_git_dependencies( def test_solver_cannot_choose_another_version_for_git_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
pendulum = get_package("pendulum", "2.0.3") pendulum = get_package("pendulum", "2.0.3")
demo = get_package("demo", "0.0.8") demo = get_package("demo", "0.0.8")
...@@ -2594,7 +2767,10 @@ def test_solver_cannot_choose_another_version_for_git_dependencies( ...@@ -2594,7 +2767,10 @@ def test_solver_cannot_choose_another_version_for_git_dependencies(
def test_solver_cannot_choose_another_version_for_url_dependencies( def test_solver_cannot_choose_another_version_for_url_dependencies(
solver, repo, package, http solver: Solver,
repo: Repository,
package: Package,
http: Type["httpretty.httpretty"],
): ):
path = ( path = (
Path(__file__).parent.parent Path(__file__).parent.parent
...@@ -2632,7 +2808,7 @@ def test_solver_cannot_choose_another_version_for_url_dependencies( ...@@ -2632,7 +2808,7 @@ def test_solver_cannot_choose_another_version_for_url_dependencies(
def test_solver_should_not_update_same_version_packages_if_installed_has_no_source_type( def test_solver_should_not_update_same_version_packages_if_installed_has_no_source_type(
solver, repo, package, installed solver: Solver, repo: Repository, package: Package, installed: InstalledRepository
): ):
package.add_dependency(Factory.create_dependency("foo", "1.0.0")) package.add_dependency(Factory.create_dependency("foo", "1.0.0"))
...@@ -2654,7 +2830,7 @@ def test_solver_should_not_update_same_version_packages_if_installed_has_no_sour ...@@ -2654,7 +2830,7 @@ def test_solver_should_not_update_same_version_packages_if_installed_has_no_sour
def test_solver_should_use_the_python_constraint_from_the_environment_if_available( def test_solver_should_use_the_python_constraint_from_the_environment_if_available(
solver, repo, package, installed solver: Solver, repo: Repository, package: Package, installed: InstalledRepository
): ):
solver.provider.set_package_python_versions("~2.7 || ^3.5") solver.provider.set_package_python_versions("~2.7 || ^3.5")
package.add_dependency(Factory.create_dependency("A", "^1.0")) package.add_dependency(Factory.create_dependency("A", "^1.0"))
...@@ -2681,7 +2857,7 @@ def test_solver_should_use_the_python_constraint_from_the_environment_if_availab ...@@ -2681,7 +2857,7 @@ def test_solver_should_use_the_python_constraint_from_the_environment_if_availab
def test_solver_should_resolve_all_versions_for_multiple_duplicate_dependencies( def test_solver_should_resolve_all_versions_for_multiple_duplicate_dependencies(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.python_versions = "~2.7 || ^3.5" package.python_versions = "~2.7 || ^3.5"
package.add_dependency( package.add_dependency(
...@@ -2729,7 +2905,7 @@ def test_solver_should_resolve_all_versions_for_multiple_duplicate_dependencies( ...@@ -2729,7 +2905,7 @@ def test_solver_should_resolve_all_versions_for_multiple_duplicate_dependencies(
def test_solver_should_not_raise_errors_for_irrelevant_python_constraints( def test_solver_should_not_raise_errors_for_irrelevant_python_constraints(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.python_versions = "^3.6" package.python_versions = "^3.6"
solver.provider.set_package_python_versions("^3.6") solver.provider.set_package_python_versions("^3.6")
...@@ -2746,7 +2922,9 @@ def test_solver_should_not_raise_errors_for_irrelevant_python_constraints( ...@@ -2746,7 +2922,9 @@ def test_solver_should_not_raise_errors_for_irrelevant_python_constraints(
check_solver_result(transaction, [{"job": "install", "package": dataclasses}]) check_solver_result(transaction, [{"job": "install", "package": dataclasses}])
def test_solver_can_resolve_transitive_extras(solver, repo, package): def test_solver_can_resolve_transitive_extras(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency(Factory.create_dependency("requests", "^2.24.0")) package.add_dependency(Factory.create_dependency("requests", "^2.24.0"))
package.add_dependency(Factory.create_dependency("PyOTA", "^2.1.0")) package.add_dependency(Factory.create_dependency("PyOTA", "^2.1.0"))
...@@ -2782,7 +2960,9 @@ def test_solver_can_resolve_transitive_extras(solver, repo, package): ...@@ -2782,7 +2960,9 @@ def test_solver_can_resolve_transitive_extras(solver, repo, package):
) )
def test_solver_can_resolve_for_packages_with_missing_extras(solver, repo, package): def test_solver_can_resolve_for_packages_with_missing_extras(
solver: Solver, repo: Repository, package: ProjectPackage
):
package.add_dependency( package.add_dependency(
Factory.create_dependency( Factory.create_dependency(
"django-anymail", {"version": "^6.0", "extras": ["postmark"]} "django-anymail", {"version": "^6.0", "extras": ["postmark"]}
...@@ -2818,7 +2998,7 @@ def test_solver_can_resolve_for_packages_with_missing_extras(solver, repo, packa ...@@ -2818,7 +2998,7 @@ def test_solver_can_resolve_for_packages_with_missing_extras(solver, repo, packa
def test_solver_can_resolve_python_restricted_package_dependencies( def test_solver_can_resolve_python_restricted_package_dependencies(
solver, repo, package, locked solver: Solver, repo: Repository, package: Package, locked: Repository
): ):
package.add_dependency( package.add_dependency(
Factory.create_dependency("futures", {"version": "^3.3.0", "python": "~2.7"}) Factory.create_dependency("futures", {"version": "^3.3.0", "python": "~2.7"})
...@@ -2851,7 +3031,7 @@ def test_solver_can_resolve_python_restricted_package_dependencies( ...@@ -2851,7 +3031,7 @@ def test_solver_can_resolve_python_restricted_package_dependencies(
def test_solver_should_not_raise_errors_for_irrelevant_transitive_python_constraints( def test_solver_should_not_raise_errors_for_irrelevant_transitive_python_constraints(
solver, repo, package solver: Solver, repo: Repository, package: Package
): ):
package.python_versions = "~2.7 || ^3.5" package.python_versions = "~2.7 || ^3.5"
solver.provider.set_package_python_versions("~2.7 || ^3.5") solver.provider.set_package_python_versions("~2.7 || ^3.5")
......
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import List
from poetry.core.packages.package import Package from poetry.core.packages.package import Package
from poetry.puzzle.transaction import Transaction from poetry.puzzle.transaction import Transaction
def check_operations(ops, expected): if TYPE_CHECKING:
from poetry.installation.operations import OperationTypes
def check_operations(
ops: List["OperationTypes"], expected: List[Dict[str, Any]]
) -> None:
for e in expected: for e in expected:
if "skipped" not in e: if "skipped" not in e:
e["skipped"] = False e["skipped"] = False
......
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Dict
from typing import List
from typing import Optional from typing import Optional
import pytest import pytest
...@@ -45,14 +47,14 @@ INSTALLED_RESULTS = [ ...@@ -45,14 +47,14 @@ INSTALLED_RESULTS = [
class MockEnv(BaseMockEnv): class MockEnv(BaseMockEnv):
@property @property
def paths(self): def paths(self) -> Dict[str, Path]:
return { return {
"purelib": SITE_PURELIB, "purelib": SITE_PURELIB,
"platlib": SITE_PLATLIB, "platlib": SITE_PLATLIB,
} }
@property @property
def sys_path(self): def sys_path(self) -> List[Path]:
return [ENV_DIR, SITE_PLATLIB, SITE_PURELIB] return [ENV_DIR, SITE_PLATLIB, SITE_PURELIB]
...@@ -91,16 +93,16 @@ def get_package_from_repository( ...@@ -91,16 +93,16 @@ def get_package_from_repository(
return None return None
def test_load_successful(repository): def test_load_successful(repository: InstalledRepository):
assert len(repository.packages) == len(INSTALLED_RESULTS) - 1 assert len(repository.packages) == len(INSTALLED_RESULTS) - 1
def test_load_ensure_isolation(repository): def test_load_ensure_isolation(repository: InstalledRepository):
package = get_package_from_repository("attrs", repository) package = get_package_from_repository("attrs", repository)
assert package is None assert package is None
def test_load_standard_package(repository): def test_load_standard_package(repository: InstalledRepository):
cleo = get_package_from_repository("cleo", repository) cleo = get_package_from_repository("cleo", repository)
assert cleo is not None assert cleo is not None
assert cleo.name == "cleo" assert cleo.name == "cleo"
...@@ -115,7 +117,7 @@ def test_load_standard_package(repository): ...@@ -115,7 +117,7 @@ def test_load_standard_package(repository):
assert foo.version.text == "0.1.0" assert foo.version.text == "0.1.0"
def test_load_git_package(repository): def test_load_git_package(repository: InstalledRepository):
pendulum = get_package_from_repository("pendulum", repository) pendulum = get_package_from_repository("pendulum", repository)
assert pendulum is not None assert pendulum is not None
assert pendulum.name == "pendulum" assert pendulum.name == "pendulum"
...@@ -129,7 +131,7 @@ def test_load_git_package(repository): ...@@ -129,7 +131,7 @@ def test_load_git_package(repository):
assert pendulum.source_reference == "bb058f6b78b2d28ef5d9a5e759cfa179a1a713d6" assert pendulum.source_reference == "bb058f6b78b2d28ef5d9a5e759cfa179a1a713d6"
def test_load_git_package_pth(repository): def test_load_git_package_pth(repository: InstalledRepository):
bender = get_package_from_repository("bender", repository) bender = get_package_from_repository("bender", repository)
assert bender is not None assert bender is not None
assert bender.name == "bender" assert bender.name == "bender"
...@@ -137,14 +139,14 @@ def test_load_git_package_pth(repository): ...@@ -137,14 +139,14 @@ def test_load_git_package_pth(repository):
assert bender.source_type == "git" assert bender.source_type == "git"
def test_load_platlib_package(repository): def test_load_platlib_package(repository: InstalledRepository):
lib64 = get_package_from_repository("lib64", repository) lib64 = get_package_from_repository("lib64", repository)
assert lib64 is not None assert lib64 is not None
assert lib64.name == "lib64" assert lib64.name == "lib64"
assert lib64.version.text == "2.3.4" assert lib64.version.text == "2.3.4"
def test_load_editable_package(repository): def test_load_editable_package(repository: InstalledRepository):
# test editable package with text .pth file # test editable package with text .pth file
editable = get_package_from_repository("editable", repository) editable = get_package_from_repository("editable", repository)
assert editable is not None assert editable is not None
...@@ -157,7 +159,7 @@ def test_load_editable_package(repository): ...@@ -157,7 +159,7 @@ def test_load_editable_package(repository):
) )
def test_load_editable_with_import_package(repository): def test_load_editable_with_import_package(repository: InstalledRepository):
# test editable package with executable .pth file # test editable package with executable .pth file
editable = get_package_from_repository("editable-with-import", repository) editable = get_package_from_repository("editable-with-import", repository)
assert editable is not None assert editable is not None
...@@ -167,7 +169,7 @@ def test_load_editable_with_import_package(repository): ...@@ -167,7 +169,7 @@ def test_load_editable_with_import_package(repository):
assert editable.source_url is None assert editable.source_url is None
def test_load_standard_package_with_pth_file(repository): def test_load_standard_package_with_pth_file(repository: InstalledRepository):
# test standard packages with .pth file is not treated as editable # test standard packages with .pth file is not treated as editable
standard = get_package_from_repository("standard", repository) standard = get_package_from_repository("standard", repository)
assert standard is not None assert standard is not None
...@@ -177,7 +179,7 @@ def test_load_standard_package_with_pth_file(repository): ...@@ -177,7 +179,7 @@ def test_load_standard_package_with_pth_file(repository):
assert standard.source_url is None assert standard.source_url is None
def test_load_pep_610_compliant_git_packages(repository): def test_load_pep_610_compliant_git_packages(repository: InstalledRepository):
package = get_package_from_repository("git-pep-610", repository) package = get_package_from_repository("git-pep-610", repository)
assert package is not None assert package is not None
...@@ -189,7 +191,7 @@ def test_load_pep_610_compliant_git_packages(repository): ...@@ -189,7 +191,7 @@ def test_load_pep_610_compliant_git_packages(repository):
assert package.source_resolved_reference == "123456" assert package.source_resolved_reference == "123456"
def test_load_pep_610_compliant_url_packages(repository): def test_load_pep_610_compliant_url_packages(repository: InstalledRepository):
package = get_package_from_repository("url-pep-610", repository) package = get_package_from_repository("url-pep-610", repository)
assert package is not None assert package is not None
...@@ -202,7 +204,7 @@ def test_load_pep_610_compliant_url_packages(repository): ...@@ -202,7 +204,7 @@ def test_load_pep_610_compliant_url_packages(repository):
) )
def test_load_pep_610_compliant_file_packages(repository): def test_load_pep_610_compliant_file_packages(repository: InstalledRepository):
package = get_package_from_repository("file-pep-610", repository) package = get_package_from_repository("file-pep-610", repository)
assert package is not None assert package is not None
...@@ -212,7 +214,7 @@ def test_load_pep_610_compliant_file_packages(repository): ...@@ -212,7 +214,7 @@ def test_load_pep_610_compliant_file_packages(repository):
assert package.source_url == "/path/to/distributions/file-pep-610-1.2.3.tar.gz" assert package.source_url == "/path/to/distributions/file-pep-610-1.2.3.tar.gz"
def test_load_pep_610_compliant_directory_packages(repository): def test_load_pep_610_compliant_directory_packages(repository: InstalledRepository):
package = get_package_from_repository("directory-pep-610", repository) package = get_package_from_repository("directory-pep-610", repository)
assert package is not None assert package is not None
...@@ -223,7 +225,9 @@ def test_load_pep_610_compliant_directory_packages(repository): ...@@ -223,7 +225,9 @@ def test_load_pep_610_compliant_directory_packages(repository):
assert not package.develop assert not package.develop
def test_load_pep_610_compliant_editable_directory_packages(repository): def test_load_pep_610_compliant_editable_directory_packages(
repository: InstalledRepository,
):
package = get_package_from_repository("editable-directory-pep-610", repository) package = get_package_from_repository("editable-directory-pep-610", repository)
assert package is not None assert package is not None
......
import shutil import shutil
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from typing import Dict
from typing import Optional
from typing import Type
import pytest import pytest
import requests import requests
...@@ -18,15 +22,20 @@ try: ...@@ -18,15 +22,20 @@ try:
except ImportError: except ImportError:
import urlparse import urlparse
if TYPE_CHECKING:
import httpretty
from _pytest.monkeypatch import MonkeyPatch
class MockRepository(LegacyRepository): class MockRepository(LegacyRepository):
FIXTURES = Path(__file__).parent / "fixtures" / "legacy" FIXTURES = Path(__file__).parent / "fixtures" / "legacy"
def __init__(self): def __init__(self) -> None:
super().__init__("legacy", url="http://legacy.foo.bar", disable_cache=True) super().__init__("legacy", url="http://legacy.foo.bar", disable_cache=True)
def _get_page(self, endpoint): def _get_page(self, endpoint: str) -> Optional[Page]:
parts = endpoint.split("/") parts = endpoint.split("/")
name = parts[1] name = parts[1]
...@@ -37,7 +46,7 @@ class MockRepository(LegacyRepository): ...@@ -37,7 +46,7 @@ class MockRepository(LegacyRepository):
with fixture.open(encoding="utf-8") as f: with fixture.open(encoding="utf-8") as f:
return Page(self._url + endpoint, f.read(), {}) return Page(self._url + endpoint, f.read(), {})
def _download(self, url, dest): def _download(self, url: str, dest: Path) -> None:
filename = urlparse.urlparse(url).path.rsplit("/")[-1] filename = urlparse.urlparse(url).path.rsplit("/")[-1]
filepath = self.FIXTURES.parent / "pypi.org" / "dists" / filename filepath = self.FIXTURES.parent / "pypi.org" / "dists" / filename
...@@ -143,8 +152,10 @@ def test_find_packages_no_prereleases(): ...@@ -143,8 +152,10 @@ def test_find_packages_no_prereleases():
assert packages[0].source_url == repo.url assert packages[0].source_url == repo.url
@pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)]) @pytest.mark.parametrize(
def test_find_packages_only_prereleases(constraint, count): ["constraint", "count"], [("*", 1), (">=1", 0), (">=19.0.0a0", 1)]
)
def test_find_packages_only_prereleases(constraint: str, count: int):
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages(Factory.create_dependency("black", constraint)) packages = repo.find_packages(Factory.create_dependency("black", constraint))
...@@ -319,7 +330,7 @@ def test_get_package_retrieves_packages_with_no_hashes(): ...@@ -319,7 +330,7 @@ def test_get_package_retrieves_packages_with_no_hashes():
class MockHttpRepository(LegacyRepository): class MockHttpRepository(LegacyRepository):
def __init__(self, endpoint_responses, http): def __init__(self, endpoint_responses: Dict, http: Type["httpretty.httpretty"]):
base_url = "http://legacy.foo.bar" base_url = "http://legacy.foo.bar"
super().__init__("legacy", url=base_url, disable_cache=True) super().__init__("legacy", url=base_url, disable_cache=True)
...@@ -328,31 +339,33 @@ class MockHttpRepository(LegacyRepository): ...@@ -328,31 +339,33 @@ class MockHttpRepository(LegacyRepository):
http.register_uri(http.GET, url, status=response) http.register_uri(http.GET, url, status=response)
def test_get_200_returns_page(http): def test_get_200_returns_page(http: Type["httpretty.httpretty"]):
repo = MockHttpRepository({"/foo": 200}, http) repo = MockHttpRepository({"/foo": 200}, http)
assert repo._get_page("/foo") assert repo._get_page("/foo")
@pytest.mark.parametrize("status_code", [401, 403, 404]) @pytest.mark.parametrize("status_code", [401, 403, 404])
def test_get_40x_and_returns_none(http, status_code): def test_get_40x_and_returns_none(http: Type["httpretty.httpretty"], status_code: int):
repo = MockHttpRepository({"/foo": status_code}, http) repo = MockHttpRepository({"/foo": status_code}, http)
assert repo._get_page("/foo") is None assert repo._get_page("/foo") is None
def test_get_5xx_raises(http): def test_get_5xx_raises(http: Type["httpretty.httpretty"]):
repo = MockHttpRepository({"/foo": 500}, http) repo = MockHttpRepository({"/foo": 500}, http)
with pytest.raises(RepositoryError): with pytest.raises(RepositoryError):
repo._get_page("/foo") repo._get_page("/foo")
def test_get_redirected_response_url(http, monkeypatch): def test_get_redirected_response_url(
http: Type["httpretty.httpretty"], monkeypatch: "MonkeyPatch"
):
repo = MockHttpRepository({"/foo": 200}, http) repo = MockHttpRepository({"/foo": 200}, http)
redirect_url = "http://legacy.redirect.bar" redirect_url = "http://legacy.redirect.bar"
def get_mock(url): def get_mock(url: str) -> requests.Response:
response = requests.Response() response = requests.Response()
response.status_code = 200 response.status_code = 200
response.url = redirect_url + "/foo" response.url = redirect_url + "/foo"
......
...@@ -3,6 +3,9 @@ import shutil ...@@ -3,6 +3,9 @@ import shutil
from io import BytesIO from io import BytesIO
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from typing import Dict
from typing import Optional
import pytest import pytest
...@@ -15,15 +18,19 @@ from poetry.repositories.pypi_repository import PyPiRepository ...@@ -15,15 +18,19 @@ from poetry.repositories.pypi_repository import PyPiRepository
from poetry.utils._compat import encode from poetry.utils._compat import encode
if TYPE_CHECKING:
from pytest_mock import MockerFixture
class MockRepository(PyPiRepository): class MockRepository(PyPiRepository):
JSON_FIXTURES = Path(__file__).parent / "fixtures" / "pypi.org" / "json" JSON_FIXTURES = Path(__file__).parent / "fixtures" / "pypi.org" / "json"
DIST_FIXTURES = Path(__file__).parent / "fixtures" / "pypi.org" / "dists" DIST_FIXTURES = Path(__file__).parent / "fixtures" / "pypi.org" / "dists"
def __init__(self, fallback=False): def __init__(self, fallback: bool = False):
super().__init__(url="http://foo.bar", disable_cache=True, fallback=fallback) super().__init__(url="http://foo.bar", disable_cache=True, fallback=fallback)
def _get(self, url): def _get(self, url: str) -> Optional[Dict]:
parts = url.split("/")[1:] parts = url.split("/")[1:]
name = parts[0] name = parts[0]
if len(parts) == 3: if len(parts) == 3:
...@@ -44,7 +51,7 @@ class MockRepository(PyPiRepository): ...@@ -44,7 +51,7 @@ class MockRepository(PyPiRepository):
with fixture.open(encoding="utf-8") as f: with fixture.open(encoding="utf-8") as f:
return json.loads(f.read()) return json.loads(f.read())
def _download(self, url, dest): def _download(self, url: str, dest: Path) -> None:
filename = url.split("/")[-1] filename = url.split("/")[-1]
fixture = self.DIST_FIXTURES / filename fixture = self.DIST_FIXTURES / filename
...@@ -73,8 +80,10 @@ def test_find_packages_does_not_select_prereleases_if_not_allowed(): ...@@ -73,8 +80,10 @@ def test_find_packages_does_not_select_prereleases_if_not_allowed():
assert len(packages) == 1 assert len(packages) == 1
@pytest.mark.parametrize("constraint,count", [("*", 1), (">=1", 0), (">=19.0.0a0", 1)]) @pytest.mark.parametrize(
def test_find_packages_only_prereleases(constraint, count): ["constraint", "count"], [("*", 1), (">=1", 0), (">=19.0.0a0", 1)]
)
def test_find_packages_only_prereleases(constraint: str, count: int):
repo = MockRepository() repo = MockRepository()
packages = repo.find_packages(Factory.create_dependency("black", constraint)) packages = repo.find_packages(Factory.create_dependency("black", constraint))
...@@ -204,7 +213,7 @@ def test_invalid_versions_ignored(): ...@@ -204,7 +213,7 @@ def test_invalid_versions_ignored():
assert len(packages) == 1 assert len(packages) == 1
def test_get_should_invalid_cache_on_too_many_redirects_error(mocker): def test_get_should_invalid_cache_on_too_many_redirects_error(mocker: "MockerFixture"):
delete_cache = mocker.patch("cachecontrol.caches.file_cache.FileCache.delete") delete_cache = mocker.patch("cachecontrol.caches.file_cache.FileCache.delete")
response = Response() response = Response()
......
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
import pytest import pytest
...@@ -12,11 +13,18 @@ from poetry.repositories.legacy_repository import LegacyRepository ...@@ -12,11 +13,18 @@ from poetry.repositories.legacy_repository import LegacyRepository
from poetry.repositories.pypi_repository import PyPiRepository from poetry.repositories.pypi_repository import PyPiRepository
if TYPE_CHECKING:
from cleo.io.io import IO
from pytest_mock import MockerFixture
from poetry.poetry import Poetry
from tests.types import FixtureDirGetter
fixtures_dir = Path(__file__).parent / "fixtures" fixtures_dir = Path(__file__).parent / "fixtures"
class MyPlugin(Plugin): class MyPlugin(Plugin):
def activate(self, poetry, io): def activate(self, poetry: "Poetry", io: "IO") -> None:
io.write_line("Updating version") io.write_line("Updating version")
poetry.package.set_version("9.9.9") poetry.package.set_version("9.9.9")
...@@ -153,13 +161,13 @@ def test_create_poetry_with_multi_constraints_dependency(): ...@@ -153,13 +161,13 @@ def test_create_poetry_with_multi_constraints_dependency():
assert len(package.requires) == 2 assert len(package.requires) == 2
def test_poetry_with_default_source(with_simple_keyring): def test_poetry_with_default_source(with_simple_keyring: None):
poetry = Factory().create_poetry(fixtures_dir / "with_default_source") poetry = Factory().create_poetry(fixtures_dir / "with_default_source")
assert len(poetry.pool.repositories) == 1 assert len(poetry.pool.repositories) == 1
def test_poetry_with_non_default_source(with_simple_keyring): def test_poetry_with_non_default_source(with_simple_keyring: None):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_source") poetry = Factory().create_poetry(fixtures_dir / "with_non_default_source")
assert len(poetry.pool.repositories) == 2 assert len(poetry.pool.repositories) == 2
...@@ -173,7 +181,7 @@ def test_poetry_with_non_default_source(with_simple_keyring): ...@@ -173,7 +181,7 @@ def test_poetry_with_non_default_source(with_simple_keyring):
assert isinstance(poetry.pool.repositories[1], PyPiRepository) assert isinstance(poetry.pool.repositories[1], PyPiRepository)
def test_poetry_with_non_default_secondary_source(with_simple_keyring): def test_poetry_with_non_default_secondary_source(with_simple_keyring: None):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_secondary_source") poetry = Factory().create_poetry(fixtures_dir / "with_non_default_secondary_source")
assert len(poetry.pool.repositories) == 2 assert len(poetry.pool.repositories) == 2
...@@ -189,7 +197,7 @@ def test_poetry_with_non_default_secondary_source(with_simple_keyring): ...@@ -189,7 +197,7 @@ def test_poetry_with_non_default_secondary_source(with_simple_keyring):
assert isinstance(repository, LegacyRepository) assert isinstance(repository, LegacyRepository)
def test_poetry_with_non_default_multiple_secondary_sources(with_simple_keyring): def test_poetry_with_non_default_multiple_secondary_sources(with_simple_keyring: None):
poetry = Factory().create_poetry( poetry = Factory().create_poetry(
fixtures_dir / "with_non_default_multiple_secondary_sources" fixtures_dir / "with_non_default_multiple_secondary_sources"
) )
...@@ -211,7 +219,7 @@ def test_poetry_with_non_default_multiple_secondary_sources(with_simple_keyring) ...@@ -211,7 +219,7 @@ def test_poetry_with_non_default_multiple_secondary_sources(with_simple_keyring)
assert isinstance(repository, LegacyRepository) assert isinstance(repository, LegacyRepository)
def test_poetry_with_non_default_multiple_sources(with_simple_keyring): def test_poetry_with_non_default_multiple_sources(with_simple_keyring: None):
poetry = Factory().create_poetry(fixtures_dir / "with_non_default_multiple_sources") poetry = Factory().create_poetry(fixtures_dir / "with_non_default_multiple_sources")
assert len(poetry.pool.repositories) == 3 assert len(poetry.pool.repositories) == 3
...@@ -242,7 +250,7 @@ def test_poetry_with_no_default_source(): ...@@ -242,7 +250,7 @@ def test_poetry_with_no_default_source():
assert isinstance(poetry.pool.repositories[0], PyPiRepository) assert isinstance(poetry.pool.repositories[0], PyPiRepository)
def test_poetry_with_two_default_sources(with_simple_keyring): def test_poetry_with_two_default_sources(with_simple_keyring: None):
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Factory().create_poetry(fixtures_dir / "with_two_default_sources") Factory().create_poetry(fixtures_dir / "with_two_default_sources")
...@@ -282,7 +290,7 @@ The Poetry configuration is invalid: ...@@ -282,7 +290,7 @@ The Poetry configuration is invalid:
assert expected == str(e.value) assert expected == str(e.value)
def test_create_poetry_with_local_config(fixture_dir): def test_create_poetry_with_local_config(fixture_dir: "FixtureDirGetter"):
poetry = Factory().create_poetry(fixture_dir("with_local_config")) poetry = Factory().create_poetry(fixture_dir("with_local_config"))
assert not poetry.config.get("virtualenvs.in-project") assert not poetry.config.get("virtualenvs.in-project")
...@@ -291,7 +299,7 @@ def test_create_poetry_with_local_config(fixture_dir): ...@@ -291,7 +299,7 @@ def test_create_poetry_with_local_config(fixture_dir):
assert not poetry.config.get("virtualenvs.options.system-site-packages") assert not poetry.config.get("virtualenvs.options.system-site-packages")
def test_create_poetry_with_plugins(mocker): def test_create_poetry_with_plugins(mocker: "MockerFixture"):
mocker.patch( mocker.patch(
"entrypoints.get_group_all", "entrypoints.get_group_all",
return_value=[EntryPoint("my-plugin", "tests.test_factory", "MyPlugin")], return_value=[EntryPoint("my-plugin", "tests.test_factory", "MyPlugin")],
......
...@@ -6,6 +6,8 @@ from tests.compat import Protocol ...@@ -6,6 +6,8 @@ from tests.compat import Protocol
if TYPE_CHECKING: if TYPE_CHECKING:
from pathlib import Path
from cleo.io.io import IO from cleo.io.io import IO
from cleo.testers.command_tester import CommandTester from cleo.testers.command_tester import CommandTester
...@@ -47,3 +49,8 @@ class ProjectFactory(Protocol): ...@@ -47,3 +49,8 @@ class ProjectFactory(Protocol):
install_deps: bool = True, install_deps: bool = True,
) -> "Poetry": ) -> "Poetry":
... ...
class FixtureDirGetter(Protocol):
def __call__(self, name: str) -> "Path":
...
import re import re
import uuid import uuid
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import List
from typing import Type
from typing import Union
import httpretty import httpretty
import pytest import pytest
import requests import requests
...@@ -11,6 +18,14 @@ from dataclasses import dataclass ...@@ -11,6 +18,14 @@ from dataclasses import dataclass
from poetry.utils.authenticator import Authenticator from poetry.utils.authenticator import Authenticator
if TYPE_CHECKING:
from _pytest.monkeypatch import MonkeyPatch
from pytest_mock import MockerFixture
from tests.conftest import Config
from tests.conftest import DummyBackend
@dataclass @dataclass
class SimpleCredential: class SimpleCredential:
username: str username: str
...@@ -18,14 +33,16 @@ class SimpleCredential: ...@@ -18,14 +33,16 @@ class SimpleCredential:
@pytest.fixture() @pytest.fixture()
def mock_remote(http): def mock_remote(http: Type[httpretty.httpretty]) -> None:
http.register_uri( http.register_uri(
http.GET, http.GET,
re.compile("^https?://foo.bar/(.+?)$"), re.compile("^https?://foo.bar/(.+?)$"),
) )
def test_authenticator_uses_url_provided_credentials(config, mock_remote, http): def test_authenticator_uses_url_provided_credentials(
config: "Config", mock_remote: None, http: Type[httpretty.httpretty]
):
config.merge( config.merge(
{ {
"repositories": {"foo": {"url": "https://foo.bar/simple/"}}, "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
...@@ -42,7 +59,7 @@ def test_authenticator_uses_url_provided_credentials(config, mock_remote, http): ...@@ -42,7 +59,7 @@ def test_authenticator_uses_url_provided_credentials(config, mock_remote, http):
def test_authenticator_uses_credentials_from_config_if_not_provided( def test_authenticator_uses_credentials_from_config_if_not_provided(
config, mock_remote, http config: "Config", mock_remote: None, http: Type[httpretty.httpretty]
): ):
config.merge( config.merge(
{ {
...@@ -60,7 +77,10 @@ def test_authenticator_uses_credentials_from_config_if_not_provided( ...@@ -60,7 +77,10 @@ def test_authenticator_uses_credentials_from_config_if_not_provided(
def test_authenticator_uses_username_only_credentials( def test_authenticator_uses_username_only_credentials(
config, mock_remote, http, with_simple_keyring config: "Config",
mock_remote: None,
http: Type[httpretty.httpretty],
with_simple_keyring: None,
): ):
config.merge( config.merge(
{ {
...@@ -77,7 +97,9 @@ def test_authenticator_uses_username_only_credentials( ...@@ -77,7 +97,9 @@ def test_authenticator_uses_username_only_credentials(
assert request.headers["Authorization"] == "Basic Zm9vMDAxOg==" assert request.headers["Authorization"] == "Basic Zm9vMDAxOg=="
def test_authenticator_uses_password_only_credentials(config, mock_remote, http): def test_authenticator_uses_password_only_credentials(
config: "Config", mock_remote: None, http: Type[httpretty.httpretty]
):
config.merge( config.merge(
{ {
"repositories": {"foo": {"url": "https://foo.bar/simple/"}}, "repositories": {"foo": {"url": "https://foo.bar/simple/"}},
...@@ -94,7 +116,10 @@ def test_authenticator_uses_password_only_credentials(config, mock_remote, http) ...@@ -94,7 +116,10 @@ def test_authenticator_uses_password_only_credentials(config, mock_remote, http)
def test_authenticator_uses_empty_strings_as_default_password( def test_authenticator_uses_empty_strings_as_default_password(
config, mock_remote, http, with_simple_keyring config: "Config",
mock_remote: None,
http: Type[httpretty.httpretty],
with_simple_keyring: None,
): ):
config.merge( config.merge(
{ {
...@@ -112,7 +137,7 @@ def test_authenticator_uses_empty_strings_as_default_password( ...@@ -112,7 +137,7 @@ def test_authenticator_uses_empty_strings_as_default_password(
def test_authenticator_uses_empty_strings_as_default_username( def test_authenticator_uses_empty_strings_as_default_username(
config, mock_remote, http config: "Config", mock_remote: None, http: Type[httpretty.httpretty]
): ):
config.merge( config.merge(
{ {
...@@ -130,7 +155,11 @@ def test_authenticator_uses_empty_strings_as_default_username( ...@@ -130,7 +155,11 @@ def test_authenticator_uses_empty_strings_as_default_username(
def test_authenticator_falls_back_to_keyring_url( def test_authenticator_falls_back_to_keyring_url(
config, mock_remote, http, with_simple_keyring, dummy_keyring config: "Config",
mock_remote: None,
http: Type[httpretty.httpretty],
with_simple_keyring: None,
dummy_keyring: "DummyBackend",
): ):
config.merge( config.merge(
{ {
...@@ -151,7 +180,11 @@ def test_authenticator_falls_back_to_keyring_url( ...@@ -151,7 +180,11 @@ def test_authenticator_falls_back_to_keyring_url(
def test_authenticator_falls_back_to_keyring_netloc( def test_authenticator_falls_back_to_keyring_netloc(
config, mock_remote, http, with_simple_keyring, dummy_keyring config: "Config",
mock_remote: None,
http: Type[httpretty.httpretty],
with_simple_keyring: None,
dummy_keyring: "DummyBackend",
): ):
config.merge( config.merge(
{ {
...@@ -170,13 +203,17 @@ def test_authenticator_falls_back_to_keyring_netloc( ...@@ -170,13 +203,17 @@ def test_authenticator_falls_back_to_keyring_netloc(
@pytest.mark.filterwarnings("ignore::pytest.PytestUnhandledThreadExceptionWarning") @pytest.mark.filterwarnings("ignore::pytest.PytestUnhandledThreadExceptionWarning")
def test_authenticator_request_retries_on_exception(mocker, config, http): def test_authenticator_request_retries_on_exception(
mocker: "MockerFixture", config: "Config", http: Type[httpretty.httpretty]
):
sleep = mocker.patch("time.sleep") sleep = mocker.patch("time.sleep")
sdist_uri = f"https://foo.bar/files/{str(uuid.uuid4())}/foo-0.1.0.tar.gz" sdist_uri = f"https://foo.bar/files/{str(uuid.uuid4())}/foo-0.1.0.tar.gz"
content = str(uuid.uuid4()) content = str(uuid.uuid4())
seen = [] seen = []
def callback(request, uri, response_headers): def callback(
request: requests.Request, uri: str, response_headers: Dict
) -> List[Union[int, Dict, str]]:
if seen.count(uri) < 2: if seen.count(uri) < 2:
seen.append(uri) seen.append(uri)
raise requests.exceptions.ConnectionError("Disconnected") raise requests.exceptions.ConnectionError("Disconnected")
...@@ -192,12 +229,12 @@ def test_authenticator_request_retries_on_exception(mocker, config, http): ...@@ -192,12 +229,12 @@ def test_authenticator_request_retries_on_exception(mocker, config, http):
@pytest.mark.filterwarnings("ignore::pytest.PytestUnhandledThreadExceptionWarning") @pytest.mark.filterwarnings("ignore::pytest.PytestUnhandledThreadExceptionWarning")
def test_authenticator_request_raises_exception_when_attempts_exhausted( def test_authenticator_request_raises_exception_when_attempts_exhausted(
mocker, config, http mocker: "MockerFixture", config: "Config", http: Type[httpretty.httpretty]
): ):
sleep = mocker.patch("time.sleep") sleep = mocker.patch("time.sleep")
sdist_uri = f"https://foo.bar/files/{str(uuid.uuid4())}/foo-0.1.0.tar.gz" sdist_uri = f"https://foo.bar/files/{str(uuid.uuid4())}/foo-0.1.0.tar.gz"
def callback(*_, **__): def callback(*_: Any, **___: Any) -> None:
raise requests.exceptions.ConnectionError(str(uuid.uuid4())) raise requests.exceptions.ConnectionError(str(uuid.uuid4()))
httpretty.register_uri(httpretty.GET, sdist_uri, body=callback) httpretty.register_uri(httpretty.GET, sdist_uri, body=callback)
...@@ -210,17 +247,32 @@ def test_authenticator_request_raises_exception_when_attempts_exhausted( ...@@ -210,17 +247,32 @@ def test_authenticator_request_raises_exception_when_attempts_exhausted(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"status, attempts", ["status", "attempts"],
[(400, 0), (401, 0), (403, 0), (404, 0), (500, 0), (502, 5), (503, 5), (504, 5)], [
(400, 0),
(401, 0),
(403, 0),
(404, 0),
(500, 0),
(502, 5),
(503, 5),
(504, 5),
],
) )
def test_authenticator_request_retries_on_status_code( def test_authenticator_request_retries_on_status_code(
mocker, config, http, status, attempts mocker: "MockerFixture",
config: "Config",
http: Type[httpretty.httpretty],
status: int,
attempts: int,
): ):
sleep = mocker.patch("time.sleep") sleep = mocker.patch("time.sleep")
sdist_uri = f"https://foo.bar/files/{str(uuid.uuid4())}/foo-0.1.0.tar.gz" sdist_uri = f"https://foo.bar/files/{str(uuid.uuid4())}/foo-0.1.0.tar.gz"
content = str(uuid.uuid4()) content = str(uuid.uuid4())
def callback(request, uri, response_headers): def callback(
request: requests.Request, uri: str, response_headers: Dict
) -> List[Union[int, Dict, str]]:
return [status, response_headers, content] return [status, response_headers, content]
httpretty.register_uri(httpretty.GET, sdist_uri, body=callback) httpretty.register_uri(httpretty.GET, sdist_uri, body=callback)
...@@ -236,13 +288,17 @@ def test_authenticator_request_retries_on_status_code( ...@@ -236,13 +288,17 @@ def test_authenticator_request_retries_on_status_code(
@pytest.fixture @pytest.fixture
def environment_repository_credentials(monkeypatch): def environment_repository_credentials(monkeypatch: "MonkeyPatch") -> None:
monkeypatch.setenv("POETRY_HTTP_BASIC_FOO_USERNAME", "bar") monkeypatch.setenv("POETRY_HTTP_BASIC_FOO_USERNAME", "bar")
monkeypatch.setenv("POETRY_HTTP_BASIC_FOO_PASSWORD", "baz") monkeypatch.setenv("POETRY_HTTP_BASIC_FOO_PASSWORD", "baz")
def test_authenticator_uses_env_provided_credentials( def test_authenticator_uses_env_provided_credentials(
config, environ, mock_remote, http, environment_repository_credentials config: "Config",
environ: None,
mock_remote: Type[httpretty.httpretty],
http: Type[httpretty.httpretty],
environment_repository_credentials: None,
): ):
config.merge({"repositories": {"foo": {"url": "https://foo.bar/simple/"}}}) config.merge({"repositories": {"foo": {"url": "https://foo.bar/simple/"}}})
......
...@@ -4,7 +4,12 @@ import subprocess ...@@ -4,7 +4,12 @@ import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any from typing import Any
from typing import Callable
from typing import Iterator
from typing import List
from typing import Optional
from typing import Union from typing import Union
import pytest import pytest
...@@ -25,6 +30,12 @@ from poetry.utils.env import SystemEnv ...@@ -25,6 +30,12 @@ from poetry.utils.env import SystemEnv
from poetry.utils.env import VirtualEnv from poetry.utils.env import VirtualEnv
if TYPE_CHECKING:
from pytest_mock import MockerFixture
from poetry.poetry import Poetry
from tests.conftest import Config
MINIMAL_SCRIPT = """\ MINIMAL_SCRIPT = """\
print("Minimal Output"), print("Minimal Output"),
...@@ -39,13 +50,18 @@ print("nullpackage loaded"), ...@@ -39,13 +50,18 @@ print("nullpackage loaded"),
class MockVirtualEnv(VirtualEnv): class MockVirtualEnv(VirtualEnv):
def __init__(self, path, base=None, sys_path=None): def __init__(
self,
path: Path,
base: Optional[Path] = None,
sys_path: Optional[List[str]] = None,
):
super().__init__(path, base=base) super().__init__(path, base=base)
self._sys_path = sys_path self._sys_path = sys_path
@property @property
def sys_path(self): def sys_path(self) -> Optional[List[str]]:
if self._sys_path is not None: if self._sys_path is not None:
return self._sys_path return self._sys_path
...@@ -53,7 +69,7 @@ class MockVirtualEnv(VirtualEnv): ...@@ -53,7 +69,7 @@ class MockVirtualEnv(VirtualEnv):
@pytest.fixture() @pytest.fixture()
def poetry(config): def poetry(config: "Config") -> "Poetry":
poetry = Factory().create_poetry( poetry = Factory().create_poetry(
Path(__file__).parent.parent / "fixtures" / "simple_project" Path(__file__).parent.parent / "fixtures" / "simple_project"
) )
...@@ -63,11 +79,13 @@ def poetry(config): ...@@ -63,11 +79,13 @@ def poetry(config):
@pytest.fixture() @pytest.fixture()
def manager(poetry): def manager(poetry: "Poetry") -> EnvManager:
return EnvManager(poetry) return EnvManager(poetry)
def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, manager): def test_virtualenvs_with_spaces_in_their_path_work_as_expected(
tmp_dir: str, manager: EnvManager
):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
manager.build_venv(str(venv_path)) manager.build_venv(str(venv_path))
...@@ -77,7 +95,9 @@ def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, manager ...@@ -77,7 +95,9 @@ def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, manager
assert venv.run("python", "-V", shell=True).startswith("Python") assert venv.run("python", "-V", shell=True).startswith("Python")
def test_env_commands_with_spaces_in_their_arg_work_as_expected(tmp_dir, manager): def test_env_commands_with_spaces_in_their_arg_work_as_expected(
tmp_dir: str, manager: EnvManager
):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
manager.build_venv(str(venv_path)) manager.build_venv(str(venv_path))
venv = VirtualEnv(venv_path) venv = VirtualEnv(venv_path)
...@@ -87,7 +107,7 @@ def test_env_commands_with_spaces_in_their_arg_work_as_expected(tmp_dir, manager ...@@ -87,7 +107,7 @@ def test_env_commands_with_spaces_in_their_arg_work_as_expected(tmp_dir, manager
def test_env_shell_commands_with_stdinput_in_their_arg_work_as_expected( def test_env_shell_commands_with_stdinput_in_their_arg_work_as_expected(
tmp_dir, manager tmp_dir: str, manager: EnvManager
): ):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
manager.build_venv(str(venv_path)) manager.build_venv(str(venv_path))
...@@ -100,7 +120,7 @@ def test_env_shell_commands_with_stdinput_in_their_arg_work_as_expected( ...@@ -100,7 +120,7 @@ def test_env_shell_commands_with_stdinput_in_their_arg_work_as_expected(
@pytest.fixture @pytest.fixture
def in_project_venv_dir(poetry): def in_project_venv_dir(poetry: "Poetry") -> Iterator[Path]:
os.environ.pop("VIRTUAL_ENV", None) os.environ.pop("VIRTUAL_ENV", None)
venv_dir = poetry.file.parent.joinpath(".venv") venv_dir = poetry.file.parent.joinpath(".venv")
venv_dir.mkdir() venv_dir.mkdir()
...@@ -112,7 +132,10 @@ def in_project_venv_dir(poetry): ...@@ -112,7 +132,10 @@ def in_project_venv_dir(poetry):
@pytest.mark.parametrize("in_project", [True, False, None]) @pytest.mark.parametrize("in_project", [True, False, None])
def test_env_get_venv_with_venv_folder_present( def test_env_get_venv_with_venv_folder_present(
manager, poetry, in_project_venv_dir, in_project manager: EnvManager,
poetry: "Poetry",
in_project_venv_dir: Path,
in_project: Optional[bool],
): ):
poetry.config.config["virtualenvs"]["in-project"] = in_project poetry.config.config["virtualenvs"]["in-project"] = in_project
venv = manager.get() venv = manager.get()
...@@ -129,8 +152,10 @@ def build_venv(path: Union[Path, str], **__: Any) -> None: ...@@ -129,8 +152,10 @@ def build_venv(path: Union[Path, str], **__: Any) -> None:
VERSION_3_7_1 = Version.parse("3.7.1") VERSION_3_7_1 = Version.parse("3.7.1")
def check_output_wrapper(version=VERSION_3_7_1): def check_output_wrapper(
def check_output(cmd, *args, **kwargs): version: Version = VERSION_3_7_1,
) -> Callable[[List[str], Any, Any], str]:
def check_output(cmd: List[str], *args: Any, **kwargs: Any) -> str:
if "sys.version_info[:3]" in cmd: if "sys.version_info[:3]" in cmd:
return version.text return version.text
elif "sys.version_info[:2]" in cmd: elif "sys.version_info[:2]" in cmd:
...@@ -142,7 +167,11 @@ def check_output_wrapper(version=VERSION_3_7_1): ...@@ -142,7 +167,11 @@ def check_output_wrapper(version=VERSION_3_7_1):
def test_activate_activates_non_existing_virtualenv_no_envs_file( def test_activate_activates_non_existing_virtualenv_no_envs_file(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -182,7 +211,11 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file( ...@@ -182,7 +211,11 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
def test_activate_activates_existing_virtualenv_no_envs_file( def test_activate_activates_existing_virtualenv_no_envs_file(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -218,7 +251,11 @@ def test_activate_activates_existing_virtualenv_no_envs_file( ...@@ -218,7 +251,11 @@ def test_activate_activates_existing_virtualenv_no_envs_file(
def test_activate_activates_same_virtualenv_with_envs_file( def test_activate_activates_same_virtualenv_with_envs_file(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -258,7 +295,11 @@ def test_activate_activates_same_virtualenv_with_envs_file( ...@@ -258,7 +295,11 @@ def test_activate_activates_same_virtualenv_with_envs_file(
def test_activate_activates_different_virtualenv_with_envs_file( def test_activate_activates_different_virtualenv_with_envs_file(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -304,7 +345,11 @@ def test_activate_activates_different_virtualenv_with_envs_file( ...@@ -304,7 +345,11 @@ def test_activate_activates_different_virtualenv_with_envs_file(
def test_activate_activates_recreates_for_different_patch( def test_activate_activates_recreates_for_different_patch(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -363,7 +408,11 @@ def test_activate_activates_recreates_for_different_patch( ...@@ -363,7 +408,11 @@ def test_activate_activates_recreates_for_different_patch(
def test_activate_does_not_recreate_when_switching_minor( def test_activate_does_not_recreate_when_switching_minor(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -410,7 +459,11 @@ def test_activate_does_not_recreate_when_switching_minor( ...@@ -410,7 +459,11 @@ def test_activate_does_not_recreate_when_switching_minor(
def test_deactivate_non_activated_but_existing( def test_deactivate_non_activated_but_existing(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -438,7 +491,13 @@ def test_deactivate_non_activated_but_existing( ...@@ -438,7 +491,13 @@ def test_deactivate_non_activated_but_existing(
assert Path("/prefix") assert Path("/prefix")
def test_deactivate_activated(tmp_dir, manager, poetry, config, mocker): def test_deactivate_activated(
tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -478,7 +537,11 @@ def test_deactivate_activated(tmp_dir, manager, poetry, config, mocker): ...@@ -478,7 +537,11 @@ def test_deactivate_activated(tmp_dir, manager, poetry, config, mocker):
def test_get_prefers_explicitly_activated_virtualenvs_over_env_var( def test_get_prefers_explicitly_activated_virtualenvs_over_env_var(
tmp_dir, manager, poetry, config, mocker tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
): ):
os.environ["VIRTUAL_ENV"] = "/environment/prefix" os.environ["VIRTUAL_ENV"] = "/environment/prefix"
...@@ -507,7 +570,7 @@ def test_get_prefers_explicitly_activated_virtualenvs_over_env_var( ...@@ -507,7 +570,7 @@ def test_get_prefers_explicitly_activated_virtualenvs_over_env_var(
assert env.base == Path("/prefix") assert env.base == Path("/prefix")
def test_list(tmp_dir, manager, poetry, config): def test_list(tmp_dir: str, manager: EnvManager, poetry: "Poetry", config: "Config"):
config.merge({"virtualenvs": {"path": str(tmp_dir)}}) config.merge({"virtualenvs": {"path": str(tmp_dir)}})
venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent))
...@@ -521,7 +584,13 @@ def test_list(tmp_dir, manager, poetry, config): ...@@ -521,7 +584,13 @@ def test_list(tmp_dir, manager, poetry, config):
assert (Path(tmp_dir) / f"{venv_name}-py3.7") == venvs[1].path assert (Path(tmp_dir) / f"{venv_name}-py3.7") == venvs[1].path
def test_remove_by_python_version(tmp_dir, manager, poetry, config, mocker): def test_remove_by_python_version(
tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
):
config.merge({"virtualenvs": {"path": str(tmp_dir)}}) config.merge({"virtualenvs": {"path": str(tmp_dir)}})
venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent))
...@@ -539,7 +608,13 @@ def test_remove_by_python_version(tmp_dir, manager, poetry, config, mocker): ...@@ -539,7 +608,13 @@ def test_remove_by_python_version(tmp_dir, manager, poetry, config, mocker):
assert not (Path(tmp_dir) / f"{venv_name}-py3.6").exists() assert not (Path(tmp_dir) / f"{venv_name}-py3.6").exists()
def test_remove_by_name(tmp_dir, manager, poetry, config, mocker): def test_remove_by_name(
tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
):
config.merge({"virtualenvs": {"path": str(tmp_dir)}}) config.merge({"virtualenvs": {"path": str(tmp_dir)}})
venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent))
...@@ -557,7 +632,13 @@ def test_remove_by_name(tmp_dir, manager, poetry, config, mocker): ...@@ -557,7 +632,13 @@ def test_remove_by_name(tmp_dir, manager, poetry, config, mocker):
assert not (Path(tmp_dir) / f"{venv_name}-py3.6").exists() assert not (Path(tmp_dir) / f"{venv_name}-py3.6").exists()
def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker): def test_remove_also_deactivates(
tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
):
config.merge({"virtualenvs": {"path": str(tmp_dir)}}) config.merge({"virtualenvs": {"path": str(tmp_dir)}})
venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent))
...@@ -583,7 +664,13 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker): ...@@ -583,7 +664,13 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker):
assert venv_name not in envs assert venv_name not in envs
def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mocker): def test_remove_keeps_dir_if_not_deleteable(
tmp_dir: str,
manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
):
# Ensure we empty rather than delete folder if its is an active mount point. # Ensure we empty rather than delete folder if its is an active mount point.
# See https://github.com/python-poetry/poetry/pull/2064 # See https://github.com/python-poetry/poetry/pull/2064
config.merge({"virtualenvs": {"path": str(tmp_dir)}}) config.merge({"virtualenvs": {"path": str(tmp_dir)}})
...@@ -608,7 +695,7 @@ def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mo ...@@ -608,7 +695,7 @@ def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mo
original_rmtree = shutil.rmtree original_rmtree = shutil.rmtree
def err_on_rm_venv_only(path, *args, **kwargs): def err_on_rm_venv_only(path: str, *args: Any, **kwargs: Any) -> None:
if path == str(venv_path): if path == str(venv_path):
raise OSError(16, "Test error") # ERRNO 16: Device or resource busy raise OSError(16, "Test error") # ERRNO 16: Device or resource busy
else: else:
...@@ -631,17 +718,17 @@ def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mo ...@@ -631,17 +718,17 @@ def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mo
@pytest.mark.skipif(os.name == "nt", reason="Symlinks are not support for Windows") @pytest.mark.skipif(os.name == "nt", reason="Symlinks are not support for Windows")
def test_env_has_symlinks_on_nix(tmp_dir, tmp_venv): def test_env_has_symlinks_on_nix(tmp_dir: str, tmp_venv: VirtualEnv):
assert os.path.islink(tmp_venv.python) assert os.path.islink(tmp_venv.python)
def test_run_with_input(tmp_dir, tmp_venv): def test_run_with_input(tmp_dir: str, tmp_venv: VirtualEnv):
result = tmp_venv.run("python", "-", input_=MINIMAL_SCRIPT) result = tmp_venv.run("python", "-", input_=MINIMAL_SCRIPT)
assert result == "Minimal Output" + os.linesep assert result == "Minimal Output" + os.linesep
def test_run_with_input_non_zero_return(tmp_dir, tmp_venv): def test_run_with_input_non_zero_return(tmp_dir: str, tmp_venv: VirtualEnv):
with pytest.raises(EnvCommandError) as process_error: with pytest.raises(EnvCommandError) as process_error:
# Test command that will return non-zero returncode. # Test command that will return non-zero returncode.
...@@ -650,14 +737,18 @@ def test_run_with_input_non_zero_return(tmp_dir, tmp_venv): ...@@ -650,14 +737,18 @@ def test_run_with_input_non_zero_return(tmp_dir, tmp_venv):
assert process_error.value.e.returncode == 1 assert process_error.value.e.returncode == 1
def test_run_with_keyboard_interrupt(tmp_dir, tmp_venv, mocker): def test_run_with_keyboard_interrupt(
tmp_dir: str, tmp_venv: VirtualEnv, mocker: "MockerFixture"
):
mocker.patch("subprocess.run", side_effect=KeyboardInterrupt()) mocker.patch("subprocess.run", side_effect=KeyboardInterrupt())
with pytest.raises(KeyboardInterrupt): with pytest.raises(KeyboardInterrupt):
tmp_venv.run("python", "-", input_=MINIMAL_SCRIPT) tmp_venv.run("python", "-", input_=MINIMAL_SCRIPT)
subprocess.run.assert_called_once() subprocess.run.assert_called_once()
def test_call_with_input_and_keyboard_interrupt(tmp_dir, tmp_venv, mocker): def test_call_with_input_and_keyboard_interrupt(
tmp_dir: str, tmp_venv: VirtualEnv, mocker: "MockerFixture"
):
mocker.patch("subprocess.run", side_effect=KeyboardInterrupt()) mocker.patch("subprocess.run", side_effect=KeyboardInterrupt())
kwargs = {"call": True} kwargs = {"call": True}
with pytest.raises(KeyboardInterrupt): with pytest.raises(KeyboardInterrupt):
...@@ -665,7 +756,9 @@ def test_call_with_input_and_keyboard_interrupt(tmp_dir, tmp_venv, mocker): ...@@ -665,7 +756,9 @@ def test_call_with_input_and_keyboard_interrupt(tmp_dir, tmp_venv, mocker):
subprocess.run.assert_called_once() subprocess.run.assert_called_once()
def test_call_no_input_with_keyboard_interrupt(tmp_dir, tmp_venv, mocker): def test_call_no_input_with_keyboard_interrupt(
tmp_dir: str, tmp_venv: VirtualEnv, mocker: "MockerFixture"
):
mocker.patch("subprocess.call", side_effect=KeyboardInterrupt()) mocker.patch("subprocess.call", side_effect=KeyboardInterrupt())
kwargs = {"call": True} kwargs = {"call": True}
with pytest.raises(KeyboardInterrupt): with pytest.raises(KeyboardInterrupt):
...@@ -673,7 +766,9 @@ def test_call_no_input_with_keyboard_interrupt(tmp_dir, tmp_venv, mocker): ...@@ -673,7 +766,9 @@ def test_call_no_input_with_keyboard_interrupt(tmp_dir, tmp_venv, mocker):
subprocess.call.assert_called_once() subprocess.call.assert_called_once()
def test_run_with_called_process_error(tmp_dir, tmp_venv, mocker): def test_run_with_called_process_error(
tmp_dir: str, tmp_venv: VirtualEnv, mocker: "MockerFixture"
):
mocker.patch( mocker.patch(
"subprocess.run", side_effect=subprocess.CalledProcessError(42, "some_command") "subprocess.run", side_effect=subprocess.CalledProcessError(42, "some_command")
) )
...@@ -682,7 +777,9 @@ def test_run_with_called_process_error(tmp_dir, tmp_venv, mocker): ...@@ -682,7 +777,9 @@ def test_run_with_called_process_error(tmp_dir, tmp_venv, mocker):
subprocess.run.assert_called_once() subprocess.run.assert_called_once()
def test_call_with_input_and_called_process_error(tmp_dir, tmp_venv, mocker): def test_call_with_input_and_called_process_error(
tmp_dir: str, tmp_venv: VirtualEnv, mocker: "MockerFixture"
):
mocker.patch( mocker.patch(
"subprocess.run", side_effect=subprocess.CalledProcessError(42, "some_command") "subprocess.run", side_effect=subprocess.CalledProcessError(42, "some_command")
) )
...@@ -692,7 +789,9 @@ def test_call_with_input_and_called_process_error(tmp_dir, tmp_venv, mocker): ...@@ -692,7 +789,9 @@ def test_call_with_input_and_called_process_error(tmp_dir, tmp_venv, mocker):
subprocess.run.assert_called_once() subprocess.run.assert_called_once()
def test_call_no_input_with_called_process_error(tmp_dir, tmp_venv, mocker): def test_call_no_input_with_called_process_error(
tmp_dir: str, tmp_venv: VirtualEnv, mocker: "MockerFixture"
):
mocker.patch( mocker.patch(
"subprocess.call", side_effect=subprocess.CalledProcessError(42, "some_command") "subprocess.call", side_effect=subprocess.CalledProcessError(42, "some_command")
) )
...@@ -703,7 +802,11 @@ def test_call_no_input_with_called_process_error(tmp_dir, tmp_venv, mocker): ...@@ -703,7 +802,11 @@ def test_call_no_input_with_called_process_error(tmp_dir, tmp_venv, mocker):
def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_ones_first( def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_ones_first(
manager, poetry, config, mocker, config_virtualenvs_path manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
config_virtualenvs_path: Path,
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -733,7 +836,11 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_ ...@@ -733,7 +836,11 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific_ones( def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific_ones(
manager, poetry, config, mocker, config_virtualenvs_path manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
config_virtualenvs_path: Path,
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -760,7 +867,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific ...@@ -760,7 +867,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific
def test_create_venv_fails_if_no_compatible_python_version_could_be_found( def test_create_venv_fails_if_no_compatible_python_version_could_be_found(
manager, poetry, config, mocker manager: EnvManager, poetry: "Poetry", config: "Config", mocker: "MockerFixture"
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -786,7 +893,7 @@ def test_create_venv_fails_if_no_compatible_python_version_could_be_found( ...@@ -786,7 +893,7 @@ def test_create_venv_fails_if_no_compatible_python_version_could_be_found(
def test_create_venv_does_not_try_to_find_compatible_versions_with_executable( def test_create_venv_does_not_try_to_find_compatible_versions_with_executable(
manager, poetry, config, mocker manager: EnvManager, poetry: "Poetry", config: "Config", mocker: "MockerFixture"
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -812,7 +919,11 @@ def test_create_venv_does_not_try_to_find_compatible_versions_with_executable( ...@@ -812,7 +919,11 @@ def test_create_venv_does_not_try_to_find_compatible_versions_with_executable(
def test_create_venv_uses_patch_version_to_detect_compatibility( def test_create_venv_uses_patch_version_to_detect_compatibility(
manager, poetry, config, mocker, config_virtualenvs_path manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
config_virtualenvs_path: Path,
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -846,7 +957,11 @@ def test_create_venv_uses_patch_version_to_detect_compatibility( ...@@ -846,7 +957,11 @@ def test_create_venv_uses_patch_version_to_detect_compatibility(
def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable( def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable(
manager, poetry, config, mocker, config_virtualenvs_path manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
config_virtualenvs_path: Path,
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -883,7 +998,11 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable( ...@@ -883,7 +998,11 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable(
def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir( def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(
manager, poetry, config, tmp_dir, mocker manager: EnvManager,
poetry: "Poetry",
config: "Config",
tmp_dir: str,
mocker: "MockerFixture",
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -934,10 +1053,10 @@ def test_system_env_has_correct_paths(): ...@@ -934,10 +1053,10 @@ def test_system_env_has_correct_paths():
@pytest.mark.parametrize( @pytest.mark.parametrize(
("enabled",), "enabled",
[(True,), (False,)], [True, False],
) )
def test_system_env_usersite(mocker, enabled): def test_system_env_usersite(mocker: "MockerFixture", enabled: bool):
mocker.patch("site.check_enableusersite", return_value=enabled) mocker.patch("site.check_enableusersite", return_value=enabled)
env = SystemEnv(Path(sys.prefix)) env = SystemEnv(Path(sys.prefix))
assert (enabled and env.usersite is not None) or ( assert (enabled and env.usersite is not None) or (
...@@ -945,7 +1064,7 @@ def test_system_env_usersite(mocker, enabled): ...@@ -945,7 +1064,7 @@ def test_system_env_usersite(mocker, enabled):
) )
def test_venv_has_correct_paths(tmp_venv): def test_venv_has_correct_paths(tmp_venv: VirtualEnv):
paths = tmp_venv.paths paths = tmp_venv.paths
assert paths.get("purelib") is not None assert paths.get("purelib") is not None
...@@ -954,16 +1073,16 @@ def test_venv_has_correct_paths(tmp_venv): ...@@ -954,16 +1073,16 @@ def test_venv_has_correct_paths(tmp_venv):
assert tmp_venv.site_packages.path == Path(paths["purelib"]) assert tmp_venv.site_packages.path == Path(paths["purelib"])
def test_env_system_packages(tmp_path, config): def test_env_system_packages(tmp_path: Path, poetry: "Poetry"):
venv_path = tmp_path / "venv" venv_path = tmp_path / "venv"
pyvenv_cfg = venv_path / "pyvenv.cfg" pyvenv_cfg = venv_path / "pyvenv.cfg"
EnvManager(config).build_venv(path=venv_path, flags={"system-site-packages": True}) EnvManager(poetry).build_venv(path=venv_path, flags={"system-site-packages": True})
assert "include-system-site-packages = true" in pyvenv_cfg.read_text() assert "include-system-site-packages = true" in pyvenv_cfg.read_text()
def test_env_finds_the_correct_executables(tmp_dir, manager): def test_env_finds_the_correct_executables(tmp_dir: str, manager: EnvManager):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
manager.build_venv(str(venv_path), with_pip=True) manager.build_venv(str(venv_path), with_pip=True)
venv = VirtualEnv(venv_path) venv = VirtualEnv(venv_path)
...@@ -999,7 +1118,9 @@ def test_env_finds_the_correct_executables(tmp_dir, manager): ...@@ -999,7 +1118,9 @@ def test_env_finds_the_correct_executables(tmp_dir, manager):
assert Path(venv.pip).name.startswith(expected_pip_executable.split(".")[0]) assert Path(venv.pip).name.startswith(expected_pip_executable.split(".")[0])
def test_env_finds_the_correct_executables_for_generic_env(tmp_dir, manager): def test_env_finds_the_correct_executables_for_generic_env(
tmp_dir: str, manager: EnvManager
):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
child_venv_path = Path(tmp_dir) / "Child Virtual Env" child_venv_path = Path(tmp_dir) / "Child Virtual Env"
manager.build_venv(str(venv_path), with_pip=True) manager.build_venv(str(venv_path), with_pip=True)
...@@ -1024,7 +1145,9 @@ def test_env_finds_the_correct_executables_for_generic_env(tmp_dir, manager): ...@@ -1024,7 +1145,9 @@ def test_env_finds_the_correct_executables_for_generic_env(tmp_dir, manager):
assert Path(venv.pip).name == expected_pip_executable assert Path(venv.pip).name == expected_pip_executable
def test_env_finds_fallback_executables_for_generic_env(tmp_dir, manager): def test_env_finds_fallback_executables_for_generic_env(
tmp_dir: str, manager: EnvManager
):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
child_venv_path = Path(tmp_dir) / "Child Virtual Env" child_venv_path = Path(tmp_dir) / "Child Virtual Env"
manager.build_venv(str(venv_path), with_pip=True) manager.build_venv(str(venv_path), with_pip=True)
...@@ -1091,7 +1214,11 @@ def test_env_finds_fallback_executables_for_generic_env(tmp_dir, manager): ...@@ -1091,7 +1214,11 @@ def test_env_finds_fallback_executables_for_generic_env(tmp_dir, manager):
def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel( def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel(
manager, poetry, config, mocker, config_virtualenvs_path manager: EnvManager,
poetry: "Poetry",
config: "Config",
mocker: "MockerFixture",
config_virtualenvs_path: Path,
): ):
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
...@@ -1122,7 +1249,7 @@ def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel( ...@@ -1122,7 +1249,7 @@ def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel(
) )
def test_generate_env_name_ignores_case_for_case_insensitive_fs(tmp_dir): def test_generate_env_name_ignores_case_for_case_insensitive_fs(tmp_dir: str):
venv_name1 = EnvManager.generate_env_name("simple-project", "MyDiR") venv_name1 = EnvManager.generate_env_name("simple-project", "MyDiR")
venv_name2 = EnvManager.generate_env_name("simple-project", "mYdIr") venv_name2 = EnvManager.generate_env_name("simple-project", "mYdIr")
if sys.platform == "win32": if sys.platform == "win32":
......
import uuid import uuid
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from poetry.utils._compat import decode from poetry.utils._compat import decode
from poetry.utils.env import SitePackages from poetry.utils.env import SitePackages
def test_env_site_simple(tmp_dir, mocker): if TYPE_CHECKING:
from pytest_mock import MockerFixture
def test_env_site_simple(tmp_dir: str, mocker: "MockerFixture"):
# emulate permission error when creating directory # emulate permission error when creating directory
mocker.patch("pathlib.Path.mkdir", side_effect=OSError()) mocker.patch("pathlib.Path.mkdir", side_effect=OSError())
site_packages = SitePackages(Path("/non-existent"), fallbacks=[Path(tmp_dir)]) site_packages = SitePackages(Path("/non-existent"), fallbacks=[Path(tmp_dir)])
...@@ -24,7 +29,7 @@ def test_env_site_simple(tmp_dir, mocker): ...@@ -24,7 +29,7 @@ def test_env_site_simple(tmp_dir, mocker):
assert not (site_packages.path / "hello.txt").exists() assert not (site_packages.path / "hello.txt").exists()
def test_env_site_select_first(tmp_dir): def test_env_site_select_first(tmp_dir: str):
path = Path(tmp_dir) path = Path(tmp_dir)
fallback = path / "fallback" fallback = path / "fallback"
fallback.mkdir(parents=True) fallback.mkdir(parents=True)
......
import sys import sys
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import Iterator
from typing import List
from typing import Optional
from typing import Set
from typing import Union
import pytest import pytest
...@@ -12,54 +20,65 @@ from poetry.repositories.legacy_repository import LegacyRepository ...@@ -12,54 +20,65 @@ from poetry.repositories.legacy_repository import LegacyRepository
from poetry.utils.exporter import Exporter from poetry.utils.exporter import Exporter
if TYPE_CHECKING:
from _pytest.capture import CaptureFixture
from pytest_mock import MockerFixture
from poetry.poetry import Poetry
from tests.conftest import Config
from tests.types import FixtureDirGetter
class Locker(BaseLocker): class Locker(BaseLocker):
def __init__(self): def __init__(self) -> None:
self._lock = TOMLFile(Path.cwd().joinpath("poetry.lock")) self._lock = TOMLFile(Path.cwd().joinpath("poetry.lock"))
self._locked = True self._locked = True
self._content_hash = self._get_content_hash() self._content_hash = self._get_content_hash()
def locked(self, is_locked=True): def locked(self, is_locked: bool = True) -> "Locker":
self._locked = is_locked self._locked = is_locked
return self return self
def mock_lock_data(self, data): def mock_lock_data(self, data: Dict[str, Any]):
self._lock_data = data self._lock_data = data
def is_locked(self): def is_locked(self) -> bool:
return self._locked return self._locked
def is_fresh(self): def is_fresh(self) -> bool:
return True return True
def _get_content_hash(self): def _get_content_hash(self) -> str:
return "123456789" return "123456789"
@pytest.fixture @pytest.fixture
def working_directory(): def working_directory() -> Path:
return Path(__file__).parent.parent.parent return Path(__file__).parent.parent.parent
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_path_cwd(mocker, working_directory): def mock_path_cwd(
mocker: "MockerFixture", working_directory: Path
) -> Iterator["MockerFixture"]:
yield mocker.patch("pathlib.Path.cwd", return_value=working_directory) yield mocker.patch("pathlib.Path.cwd", return_value=working_directory)
@pytest.fixture() @pytest.fixture()
def locker(): def locker() -> Locker:
return Locker() return Locker()
@pytest.fixture @pytest.fixture
def poetry(fixture_dir, locker): def poetry(fixture_dir: "FixtureDirGetter", locker: Locker) -> "Poetry":
p = Factory().create_poetry(fixture_dir("sample_project")) p = Factory().create_poetry(fixture_dir("sample_project"))
p._locker = locker p._locker = locker
return p return p
def set_package_requires(poetry, skip=None): def set_package_requires(poetry: "Poetry", skip: Optional[Set[str]] = None) -> None:
skip = skip or set() skip = skip or set()
packages = poetry.locker.locked_repository(with_dev_reqs=True).packages packages = poetry.locker.locked_repository(with_dev_reqs=True).packages
package = poetry.package.with_dependency_groups([], only=True) package = poetry.package.with_dependency_groups([], only=True)
...@@ -71,7 +90,7 @@ def set_package_requires(poetry, skip=None): ...@@ -71,7 +90,7 @@ def set_package_requires(poetry, skip=None):
def test_exporter_can_export_requirements_txt_with_standard_packages( def test_exporter_can_export_requirements_txt_with_standard_packages(
tmp_dir, poetry, mocker tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -116,7 +135,7 @@ foo==1.2.3 ...@@ -116,7 +135,7 @@ foo==1.2.3
def test_exporter_can_export_requirements_txt_with_standard_packages_and_markers( def test_exporter_can_export_requirements_txt_with_standard_packages_and_markers(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -171,7 +190,7 @@ foo==1.2.3 ; python_version < "3.7" ...@@ -171,7 +190,7 @@ foo==1.2.3 ; python_version < "3.7"
assert expected == content assert expected == content
def test_exporter_can_export_requirements_txt_poetry(tmp_dir, poetry): def test_exporter_can_export_requirements_txt_poetry(tmp_dir: str, poetry: "Poetry"):
"""Regression test for #3254""" """Regression test for #3254"""
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
...@@ -289,7 +308,9 @@ def test_exporter_can_export_requirements_txt_poetry(tmp_dir, poetry): ...@@ -289,7 +308,9 @@ def test_exporter_can_export_requirements_txt_poetry(tmp_dir, poetry):
assert dependency.marker == expected_dependency.marker assert dependency.marker == expected_dependency.marker
def test_exporter_can_export_requirements_txt_pyinstaller(tmp_dir, poetry): def test_exporter_can_export_requirements_txt_pyinstaller(
tmp_dir: str, poetry: "Poetry"
):
"""Regression test for #3254""" """Regression test for #3254"""
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
...@@ -366,7 +387,7 @@ def test_exporter_can_export_requirements_txt_pyinstaller(tmp_dir, poetry): ...@@ -366,7 +387,7 @@ def test_exporter_can_export_requirements_txt_pyinstaller(tmp_dir, poetry):
def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers( def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -446,11 +467,11 @@ def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers( ...@@ -446,11 +467,11 @@ def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"dev,lines", ["dev", "lines"],
[(False, ['a==1.2.3 ; python_version < "3.8"']), (True, ["a==1.2.3", "b==4.5.6"])], [(False, ['a==1.2.3 ; python_version < "3.8"']), (True, ["a==1.2.3", "b==4.5.6"])],
) )
def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers_any( def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers_any(
tmp_dir, poetry, dev, lines tmp_dir: str, poetry: "Poetry", dev: bool, lines: List[str]
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -503,7 +524,7 @@ def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers_a ...@@ -503,7 +524,7 @@ def test_exporter_can_export_requirements_txt_with_nested_packages_and_markers_a
def test_exporter_can_export_requirements_txt_with_standard_packages_and_hashes( def test_exporter_can_export_requirements_txt_with_standard_packages_and_hashes(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -550,7 +571,7 @@ foo==1.2.3 \\ ...@@ -550,7 +571,7 @@ foo==1.2.3 \\
def test_exporter_can_export_requirements_txt_with_standard_packages_and_hashes_disabled( def test_exporter_can_export_requirements_txt_with_standard_packages_and_hashes_disabled(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -597,7 +618,7 @@ foo==1.2.3 ...@@ -597,7 +618,7 @@ foo==1.2.3
def test_exporter_exports_requirements_txt_without_dev_packages_by_default( def test_exporter_exports_requirements_txt_without_dev_packages_by_default(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -642,7 +663,7 @@ foo==1.2.3 \\ ...@@ -642,7 +663,7 @@ foo==1.2.3 \\
def test_exporter_exports_requirements_txt_with_dev_packages_if_opted_in( def test_exporter_exports_requirements_txt_with_dev_packages_if_opted_in(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -688,7 +709,9 @@ foo==1.2.3 \\ ...@@ -688,7 +709,9 @@ foo==1.2.3 \\
assert expected == content assert expected == content
def test_exporter_exports_requirements_txt_without_optional_packages(tmp_dir, poetry): def test_exporter_exports_requirements_txt_without_optional_packages(
tmp_dir: str, poetry: "Poetry"
):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
"package": [ "package": [
...@@ -732,7 +755,7 @@ foo==1.2.3 \\ ...@@ -732,7 +755,7 @@ foo==1.2.3 \\
@pytest.mark.parametrize( @pytest.mark.parametrize(
"extras,lines", ["extras", "lines"],
[ [
(None, ["foo==1.2.3"]), (None, ["foo==1.2.3"]),
(False, ["foo==1.2.3"]), (False, ["foo==1.2.3"]),
...@@ -741,7 +764,10 @@ foo==1.2.3 \\ ...@@ -741,7 +764,10 @@ foo==1.2.3 \\
], ],
) )
def test_exporter_exports_requirements_txt_with_optional_packages( def test_exporter_exports_requirements_txt_with_optional_packages(
tmp_dir, poetry, extras, lines tmp_dir: str,
poetry: "Poetry",
extras: Optional[Union[bool, List[str]]],
lines: List[str],
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -798,7 +824,9 @@ def test_exporter_exports_requirements_txt_with_optional_packages( ...@@ -798,7 +824,9 @@ def test_exporter_exports_requirements_txt_with_optional_packages(
assert content.strip() == expected assert content.strip() == expected
def test_exporter_can_export_requirements_txt_with_git_packages(tmp_dir, poetry): def test_exporter_can_export_requirements_txt_with_git_packages(
tmp_dir: str, poetry: "Poetry"
):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
"package": [ "package": [
...@@ -838,7 +866,9 @@ foo @ git+https://github.com/foo/foo.git@123456 ...@@ -838,7 +866,9 @@ foo @ git+https://github.com/foo/foo.git@123456
assert expected == content assert expected == content
def test_exporter_can_export_requirements_txt_with_nested_packages(tmp_dir, poetry): def test_exporter_can_export_requirements_txt_with_nested_packages(
tmp_dir: str, poetry: "Poetry"
):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
"package": [ "package": [
...@@ -888,7 +918,7 @@ foo @ git+https://github.com/foo/foo.git@123456 ...@@ -888,7 +918,7 @@ foo @ git+https://github.com/foo/foo.git@123456
def test_exporter_can_export_requirements_txt_with_nested_packages_cyclic( def test_exporter_can_export_requirements_txt_with_nested_packages_cyclic(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -944,7 +974,7 @@ foo==1.2.3 ...@@ -944,7 +974,7 @@ foo==1.2.3
def test_exporter_can_export_requirements_txt_with_nested_packages_and_multiple_markers( def test_exporter_can_export_requirements_txt_with_nested_packages_and_multiple_markers(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1017,7 +1047,7 @@ foo==1.2.3 ...@@ -1017,7 +1047,7 @@ foo==1.2.3
def test_exporter_can_export_requirements_txt_with_git_packages_and_markers( def test_exporter_can_export_requirements_txt_with_git_packages_and_markers(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1060,7 +1090,7 @@ foo @ git+https://github.com/foo/foo.git@123456 ; python_version < "3.7" ...@@ -1060,7 +1090,7 @@ foo @ git+https://github.com/foo/foo.git@123456 ; python_version < "3.7"
def test_exporter_can_export_requirements_txt_with_directory_packages( def test_exporter_can_export_requirements_txt_with_directory_packages(
tmp_dir, poetry, working_directory tmp_dir: str, poetry: "Poetry", working_directory: Path
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1104,7 +1134,7 @@ foo @ {}/tests/fixtures/sample_project ...@@ -1104,7 +1134,7 @@ foo @ {}/tests/fixtures/sample_project
def test_exporter_can_export_requirements_txt_with_nested_directory_packages( def test_exporter_can_export_requirements_txt_with_nested_directory_packages(
tmp_dir, poetry, working_directory tmp_dir: str, poetry: "Poetry", working_directory: Path
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1176,7 +1206,7 @@ foo @ {}/tests/fixtures/sample_project ...@@ -1176,7 +1206,7 @@ foo @ {}/tests/fixtures/sample_project
def test_exporter_can_export_requirements_txt_with_directory_packages_and_markers( def test_exporter_can_export_requirements_txt_with_directory_packages_and_markers(
tmp_dir, poetry, working_directory tmp_dir: str, poetry: "Poetry", working_directory: Path
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1221,7 +1251,7 @@ foo @ {}/tests/fixtures/sample_project ; python_version < "3.7" ...@@ -1221,7 +1251,7 @@ foo @ {}/tests/fixtures/sample_project ; python_version < "3.7"
def test_exporter_can_export_requirements_txt_with_file_packages( def test_exporter_can_export_requirements_txt_with_file_packages(
tmp_dir, poetry, working_directory tmp_dir: str, poetry: "Poetry", working_directory: Path
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1265,7 +1295,7 @@ foo @ {}/tests/fixtures/distributions/demo-0.1.0.tar.gz ...@@ -1265,7 +1295,7 @@ foo @ {}/tests/fixtures/distributions/demo-0.1.0.tar.gz
def test_exporter_can_export_requirements_txt_with_file_packages_and_markers( def test_exporter_can_export_requirements_txt_with_file_packages_and_markers(
tmp_dir, poetry, working_directory tmp_dir: str, poetry: "Poetry", working_directory: Path
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1309,7 +1339,9 @@ foo @ {}/tests/fixtures/distributions/demo-0.1.0.tar.gz ; python_version < "3.7" ...@@ -1309,7 +1339,9 @@ foo @ {}/tests/fixtures/distributions/demo-0.1.0.tar.gz ; python_version < "3.7"
assert expected == content assert expected == content
def test_exporter_exports_requirements_txt_with_legacy_packages(tmp_dir, poetry): def test_exporter_exports_requirements_txt_with_legacy_packages(
tmp_dir: str, poetry: "Poetry"
):
poetry.pool.add_repository( poetry.pool.add_repository(
LegacyRepository( LegacyRepository(
"custom", "custom",
...@@ -1367,7 +1399,9 @@ foo==1.2.3 \\ ...@@ -1367,7 +1399,9 @@ foo==1.2.3 \\
assert expected == content assert expected == content
def test_exporter_exports_requirements_txt_with_url_false(tmp_dir, poetry): def test_exporter_exports_requirements_txt_with_url_false(
tmp_dir: str, poetry: "Poetry"
):
poetry.pool.add_repository( poetry.pool.add_repository(
LegacyRepository( LegacyRepository(
"custom", "custom",
...@@ -1426,7 +1460,7 @@ foo==1.2.3 \\ ...@@ -1426,7 +1460,7 @@ foo==1.2.3 \\
def test_exporter_exports_requirements_txt_with_legacy_packages_trusted_host( def test_exporter_exports_requirements_txt_with_legacy_packages_trusted_host(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.pool.add_repository( poetry.pool.add_repository(
LegacyRepository( LegacyRepository(
...@@ -1477,14 +1511,14 @@ bar==4.5.6 \\ ...@@ -1477,14 +1511,14 @@ bar==4.5.6 \\
@pytest.mark.parametrize( @pytest.mark.parametrize(
("dev", "expected"), ["dev", "expected"],
[ [
(True, ["bar==1.2.2", "baz==1.2.3", "foo==1.2.1"]), (True, ["bar==1.2.2", "baz==1.2.3", "foo==1.2.1"]),
(False, ["bar==1.2.2", "foo==1.2.1"]), (False, ["bar==1.2.2", "foo==1.2.1"]),
], ],
) )
def test_exporter_exports_requirements_txt_with_dev_extras( def test_exporter_exports_requirements_txt_with_dev_extras(
tmp_dir, poetry, dev, expected tmp_dir: str, poetry: "Poetry", dev: bool, expected: List[str]
): ):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
...@@ -1539,7 +1573,7 @@ def test_exporter_exports_requirements_txt_with_dev_extras( ...@@ -1539,7 +1573,7 @@ def test_exporter_exports_requirements_txt_with_dev_extras(
def test_exporter_exports_requirements_txt_with_legacy_packages_and_duplicate_sources( def test_exporter_exports_requirements_txt_with_legacy_packages_and_duplicate_sources(
tmp_dir, poetry tmp_dir: str, poetry: "Poetry"
): ):
poetry.pool.add_repository( poetry.pool.add_repository(
LegacyRepository( LegacyRepository(
...@@ -1625,7 +1659,7 @@ foo==1.2.3 \\ ...@@ -1625,7 +1659,7 @@ foo==1.2.3 \\
def test_exporter_exports_requirements_txt_with_legacy_packages_and_credentials( def test_exporter_exports_requirements_txt_with_legacy_packages_and_credentials(
tmp_dir, poetry, config tmp_dir: str, poetry: "Poetry", config: "Config"
): ):
poetry.config.merge( poetry.config.merge(
{ {
...@@ -1693,7 +1727,9 @@ foo==1.2.3 \\ ...@@ -1693,7 +1727,9 @@ foo==1.2.3 \\
assert expected == content assert expected == content
def test_exporter_exports_requirements_txt_to_standard_output(tmp_dir, poetry, capsys): def test_exporter_exports_requirements_txt_to_standard_output(
tmp_dir: str, poetry: "Poetry", capsys: "CaptureFixture"
):
poetry.locker.mock_lock_data( poetry.locker.mock_lock_data(
{ {
"package": [ "package": [
......
from typing import Dict
from typing import List
import pytest import pytest
from poetry.core.packages.package import Package from poetry.core.packages.package import Package
...@@ -18,7 +21,7 @@ _PACKAGE_QUIX.add_dependency(Factory.create_dependency("baz", "*")) ...@@ -18,7 +21,7 @@ _PACKAGE_QUIX.add_dependency(Factory.create_dependency("baz", "*"))
@pytest.mark.parametrize( @pytest.mark.parametrize(
"packages,extras,extra_names,expected_extra_package_names", ["packages", "extras", "extra_names", "expected_extra_package_names"],
[ [
# Empty edge case # Empty edge case
([], {}, [], []), ([], {}, [], []),
...@@ -56,7 +59,10 @@ _PACKAGE_QUIX.add_dependency(Factory.create_dependency("baz", "*")) ...@@ -56,7 +59,10 @@ _PACKAGE_QUIX.add_dependency(Factory.create_dependency("baz", "*"))
], ],
) )
def test_get_extra_package_names( def test_get_extra_package_names(
packages, extras, extra_names, expected_extra_package_names packages: List[Package],
extras: Dict[str, List[str]],
extra_names: List[str],
expected_extra_package_names: List[str],
): ):
assert expected_extra_package_names == list( assert expected_extra_package_names == list(
get_extra_package_names(packages, extras, extra_names) get_extra_package_names(packages, extras, extra_names)
......
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from poetry.core.utils.helpers import parse_requires from poetry.core.utils.helpers import parse_requires
from poetry.utils.helpers import get_cert from poetry.utils.helpers import get_cert
from poetry.utils.helpers import get_client_cert from poetry.utils.helpers import get_client_cert
if TYPE_CHECKING:
from tests.conftest import Config
def test_parse_requires(): def test_parse_requires():
requires = """\ requires = """\
jsonschema>=2.6.0.0,<3.0.0.0 jsonschema>=2.6.0.0,<3.0.0.0
...@@ -58,14 +63,14 @@ isort@ git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e5283576 ...@@ -58,14 +63,14 @@ isort@ git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e5283576
assert result == expected assert result == expected
def test_get_cert(config): def test_get_cert(config: "Config"):
ca_cert = "path/to/ca.pem" ca_cert = "path/to/ca.pem"
config.merge({"certificates": {"foo": {"cert": ca_cert}}}) config.merge({"certificates": {"foo": {"cert": ca_cert}}})
assert get_cert(config, "foo") == Path(ca_cert) assert get_cert(config, "foo") == Path(ca_cert)
def test_get_client_cert(config): def test_get_client_cert(config: "Config"):
client_cert = "path/to/client.pem" client_cert = "path/to/client.pem"
config.merge({"certificates": {"foo": {"client-cert": client_cert}}}) config.merge({"certificates": {"foo": {"client-cert": client_cert}}})
......
import os import os
from typing import TYPE_CHECKING
import pytest import pytest
from poetry.utils.password_manager import KeyRing from poetry.utils.password_manager import KeyRing
...@@ -7,7 +9,16 @@ from poetry.utils.password_manager import KeyRingError ...@@ -7,7 +9,16 @@ from poetry.utils.password_manager import KeyRingError
from poetry.utils.password_manager import PasswordManager from poetry.utils.password_manager import PasswordManager
def test_set_http_password(config, with_simple_keyring, dummy_keyring): if TYPE_CHECKING:
from pytest_mock import MockerFixture
from tests.conftest import Config
from tests.conftest import DummyBackend
def test_set_http_password(
config: "Config", with_simple_keyring: None, dummy_keyring: "DummyBackend"
):
manager = PasswordManager(config) manager = PasswordManager(config)
assert manager.keyring.is_available() assert manager.keyring.is_available()
...@@ -20,7 +31,9 @@ def test_set_http_password(config, with_simple_keyring, dummy_keyring): ...@@ -20,7 +31,9 @@ def test_set_http_password(config, with_simple_keyring, dummy_keyring):
assert "password" not in auth assert "password" not in auth
def test_get_http_auth(config, with_simple_keyring, dummy_keyring): def test_get_http_auth(
config: "Config", with_simple_keyring: None, dummy_keyring: "DummyBackend"
):
dummy_keyring.set_password("poetry-repository-foo", "bar", "baz") dummy_keyring.set_password("poetry-repository-foo", "bar", "baz")
config.auth_config_source.add_property("http-basic.foo", {"username": "bar"}) config.auth_config_source.add_property("http-basic.foo", {"username": "bar"})
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -32,7 +45,9 @@ def test_get_http_auth(config, with_simple_keyring, dummy_keyring): ...@@ -32,7 +45,9 @@ def test_get_http_auth(config, with_simple_keyring, dummy_keyring):
assert auth["password"] == "baz" assert auth["password"] == "baz"
def test_delete_http_password(config, with_simple_keyring, dummy_keyring): def test_delete_http_password(
config: "Config", with_simple_keyring: None, dummy_keyring: "DummyBackend"
):
dummy_keyring.set_password("poetry-repository-foo", "bar", "baz") dummy_keyring.set_password("poetry-repository-foo", "bar", "baz")
config.auth_config_source.add_property("http-basic.foo", {"username": "bar"}) config.auth_config_source.add_property("http-basic.foo", {"username": "bar"})
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -44,7 +59,9 @@ def test_delete_http_password(config, with_simple_keyring, dummy_keyring): ...@@ -44,7 +59,9 @@ def test_delete_http_password(config, with_simple_keyring, dummy_keyring):
assert config.get("http-basic.foo") is None assert config.get("http-basic.foo") is None
def test_set_pypi_token(config, with_simple_keyring, dummy_keyring): def test_set_pypi_token(
config: "Config", with_simple_keyring: None, dummy_keyring: "DummyBackend"
):
manager = PasswordManager(config) manager = PasswordManager(config)
assert manager.keyring.is_available() assert manager.keyring.is_available()
...@@ -55,7 +72,9 @@ def test_set_pypi_token(config, with_simple_keyring, dummy_keyring): ...@@ -55,7 +72,9 @@ def test_set_pypi_token(config, with_simple_keyring, dummy_keyring):
assert dummy_keyring.get_password("poetry-repository-foo", "__token__") == "baz" assert dummy_keyring.get_password("poetry-repository-foo", "__token__") == "baz"
def test_get_pypi_token(config, with_simple_keyring, dummy_keyring): def test_get_pypi_token(
config: "Config", with_simple_keyring: None, dummy_keyring: "DummyBackend"
):
dummy_keyring.set_password("poetry-repository-foo", "__token__", "baz") dummy_keyring.set_password("poetry-repository-foo", "__token__", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -63,7 +82,9 @@ def test_get_pypi_token(config, with_simple_keyring, dummy_keyring): ...@@ -63,7 +82,9 @@ def test_get_pypi_token(config, with_simple_keyring, dummy_keyring):
assert manager.get_pypi_token("foo") == "baz" assert manager.get_pypi_token("foo") == "baz"
def test_delete_pypi_token(config, with_simple_keyring, dummy_keyring): def test_delete_pypi_token(
config: "Config", with_simple_keyring: None, dummy_keyring: "DummyBackend"
):
dummy_keyring.set_password("poetry-repository-foo", "__token__", "baz") dummy_keyring.set_password("poetry-repository-foo", "__token__", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -73,7 +94,9 @@ def test_delete_pypi_token(config, with_simple_keyring, dummy_keyring): ...@@ -73,7 +94,9 @@ def test_delete_pypi_token(config, with_simple_keyring, dummy_keyring):
assert dummy_keyring.get_password("poetry-repository-foo", "__token__") is None assert dummy_keyring.get_password("poetry-repository-foo", "__token__") is None
def test_set_http_password_with_unavailable_backend(config, with_fail_keyring): def test_set_http_password_with_unavailable_backend(
config: "Config", with_fail_keyring: None
):
manager = PasswordManager(config) manager = PasswordManager(config)
assert not manager.keyring.is_available() assert not manager.keyring.is_available()
...@@ -84,7 +107,9 @@ def test_set_http_password_with_unavailable_backend(config, with_fail_keyring): ...@@ -84,7 +107,9 @@ def test_set_http_password_with_unavailable_backend(config, with_fail_keyring):
assert auth["password"] == "baz" assert auth["password"] == "baz"
def test_get_http_auth_with_unavailable_backend(config, with_fail_keyring): def test_get_http_auth_with_unavailable_backend(
config: "Config", with_fail_keyring: None
):
config.auth_config_source.add_property( config.auth_config_source.add_property(
"http-basic.foo", {"username": "bar", "password": "baz"} "http-basic.foo", {"username": "bar", "password": "baz"}
) )
...@@ -97,7 +122,9 @@ def test_get_http_auth_with_unavailable_backend(config, with_fail_keyring): ...@@ -97,7 +122,9 @@ def test_get_http_auth_with_unavailable_backend(config, with_fail_keyring):
assert auth["password"] == "baz" assert auth["password"] == "baz"
def test_delete_http_password_with_unavailable_backend(config, with_fail_keyring): def test_delete_http_password_with_unavailable_backend(
config: "Config", with_fail_keyring: None
):
config.auth_config_source.add_property( config.auth_config_source.add_property(
"http-basic.foo", {"username": "bar", "password": "baz"} "http-basic.foo", {"username": "bar", "password": "baz"}
) )
...@@ -109,7 +136,9 @@ def test_delete_http_password_with_unavailable_backend(config, with_fail_keyring ...@@ -109,7 +136,9 @@ def test_delete_http_password_with_unavailable_backend(config, with_fail_keyring
assert config.get("http-basic.foo") is None assert config.get("http-basic.foo") is None
def test_set_pypi_token_with_unavailable_backend(config, with_fail_keyring): def test_set_pypi_token_with_unavailable_backend(
config: "Config", with_fail_keyring: None
):
manager = PasswordManager(config) manager = PasswordManager(config)
assert not manager.keyring.is_available() assert not manager.keyring.is_available()
...@@ -118,7 +147,9 @@ def test_set_pypi_token_with_unavailable_backend(config, with_fail_keyring): ...@@ -118,7 +147,9 @@ def test_set_pypi_token_with_unavailable_backend(config, with_fail_keyring):
assert config.get("pypi-token.foo") == "baz" assert config.get("pypi-token.foo") == "baz"
def test_get_pypi_token_with_unavailable_backend(config, with_fail_keyring): def test_get_pypi_token_with_unavailable_backend(
config: "Config", with_fail_keyring: None
):
config.auth_config_source.add_property("pypi-token.foo", "baz") config.auth_config_source.add_property("pypi-token.foo", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -126,7 +157,9 @@ def test_get_pypi_token_with_unavailable_backend(config, with_fail_keyring): ...@@ -126,7 +157,9 @@ def test_get_pypi_token_with_unavailable_backend(config, with_fail_keyring):
assert manager.get_pypi_token("foo") == "baz" assert manager.get_pypi_token("foo") == "baz"
def test_delete_pypi_token_with_unavailable_backend(config, with_fail_keyring): def test_delete_pypi_token_with_unavailable_backend(
config: "Config", with_fail_keyring: None
):
config.auth_config_source.add_property("pypi-token.foo", "baz") config.auth_config_source.add_property("pypi-token.foo", "baz")
manager = PasswordManager(config) manager = PasswordManager(config)
...@@ -136,7 +169,9 @@ def test_delete_pypi_token_with_unavailable_backend(config, with_fail_keyring): ...@@ -136,7 +169,9 @@ def test_delete_pypi_token_with_unavailable_backend(config, with_fail_keyring):
assert config.get("pypi-token.foo") is None assert config.get("pypi-token.foo") is None
def test_keyring_raises_errors_on_keyring_errors(mocker, with_fail_keyring): def test_keyring_raises_errors_on_keyring_errors(
mocker: "MockerFixture", with_fail_keyring: None
):
mocker.patch("poetry.utils.password_manager.KeyRing._check") mocker.patch("poetry.utils.password_manager.KeyRing._check")
key_ring = KeyRing("poetry") key_ring = KeyRing("poetry")
...@@ -151,14 +186,16 @@ def test_keyring_raises_errors_on_keyring_errors(mocker, with_fail_keyring): ...@@ -151,14 +186,16 @@ def test_keyring_raises_errors_on_keyring_errors(mocker, with_fail_keyring):
def test_keyring_with_chainer_backend_and_not_compatible_only_should_be_unavailable( def test_keyring_with_chainer_backend_and_not_compatible_only_should_be_unavailable(
with_chained_keyring, with_chained_keyring: None,
): ):
key_ring = KeyRing("poetry") key_ring = KeyRing("poetry")
assert not key_ring.is_available() assert not key_ring.is_available()
def test_get_http_auth_from_environment_variables(environ, config, with_simple_keyring): def test_get_http_auth_from_environment_variables(
environ: None, config: "Config", with_simple_keyring: None
):
os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar" os.environ["POETRY_HTTP_BASIC_FOO_USERNAME"] = "bar"
os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz" os.environ["POETRY_HTTP_BASIC_FOO_PASSWORD"] = "baz"
......
from typing import Dict
from typing import Optional
import pytest import pytest
from poetry.utils import patterns from poetry.utils import patterns
...@@ -32,7 +35,7 @@ from poetry.utils import patterns ...@@ -32,7 +35,7 @@ from poetry.utils import patterns
), ),
], ],
) )
def test_wheel_file_re(filename, expected): def test_wheel_file_re(filename: str, expected: Dict[str, Optional[str]]):
match = patterns.wheel_file_re.match(filename) match = patterns.wheel_file_re.match(filename)
groups = match.groupdict() groups = match.groupdict()
......
import subprocess import subprocess
from typing import TYPE_CHECKING
import pytest import pytest
from poetry.core.packages.utils.link import Link from poetry.core.packages.utils.link import Link
...@@ -7,14 +9,25 @@ from poetry.core.packages.utils.utils import path_to_url ...@@ -7,14 +9,25 @@ from poetry.core.packages.utils.utils import path_to_url
from poetry.utils.pip import pip_install from poetry.utils.pip import pip_install
def test_pip_install_successful(tmp_dir, tmp_venv, fixture_dir): if TYPE_CHECKING:
from pytest_mock import MockerFixture
from poetry.utils.env import VirtualEnv
from tests.types import FixtureDirGetter
def test_pip_install_successful(
tmp_dir: str, tmp_venv: "VirtualEnv", fixture_dir: "FixtureDirGetter"
):
file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl") file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl")
result = pip_install(file_path, tmp_venv) result = pip_install(file_path, tmp_venv)
assert "Successfully installed demo-0.1.0" in result assert "Successfully installed demo-0.1.0" in result
def test_pip_install_link(tmp_dir, tmp_venv, fixture_dir): def test_pip_install_link(
tmp_dir: str, tmp_venv: "VirtualEnv", fixture_dir: "FixtureDirGetter"
):
file_path = Link( file_path = Link(
path_to_url(fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl")) path_to_url(fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl"))
) )
...@@ -23,7 +36,12 @@ def test_pip_install_link(tmp_dir, tmp_venv, fixture_dir): ...@@ -23,7 +36,12 @@ def test_pip_install_link(tmp_dir, tmp_venv, fixture_dir):
assert "Successfully installed demo-0.1.0" in result assert "Successfully installed demo-0.1.0" in result
def test_pip_install_with_keyboard_interrupt(tmp_dir, tmp_venv, fixture_dir, mocker): def test_pip_install_with_keyboard_interrupt(
tmp_dir: str,
tmp_venv: "VirtualEnv",
fixture_dir: "FixtureDirGetter",
mocker: "MockerFixture",
):
file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl") file_path = fixture_dir("distributions/demo-0.1.0-py2.py3-none-any.whl")
mocker.patch("subprocess.run", side_effect=KeyboardInterrupt()) mocker.patch("subprocess.run", side_effect=KeyboardInterrupt())
with pytest.raises(KeyboardInterrupt): with pytest.raises(KeyboardInterrupt):
......
import os import os
from typing import Callable
import pytest import pytest
from poetry.core.version.exceptions import InvalidVersion from poetry.core.version.exceptions import InvalidVersion
...@@ -7,14 +9,16 @@ from poetry.utils.setup_reader import SetupReader ...@@ -7,14 +9,16 @@ from poetry.utils.setup_reader import SetupReader
@pytest.fixture() @pytest.fixture()
def setup(): def setup() -> Callable[[str], str]:
def _setup(name): def _setup(name: str) -> str:
return os.path.join(os.path.dirname(__file__), "fixtures", "setups", name) return os.path.join(os.path.dirname(__file__), "fixtures", "setups", name)
return _setup return _setup
def test_setup_reader_read_first_level_setup_call_with_direct_types(setup): def test_setup_reader_read_first_level_setup_call_with_direct_types(
setup: Callable[[str], str]
):
result = SetupReader.read_from_directory(setup("flask")) result = SetupReader.read_from_directory(setup("flask"))
expected_name = "Flask" expected_name = "Flask"
...@@ -46,7 +50,9 @@ def test_setup_reader_read_first_level_setup_call_with_direct_types(setup): ...@@ -46,7 +50,9 @@ def test_setup_reader_read_first_level_setup_call_with_direct_types(setup):
assert expected_python_requires == result["python_requires"] assert expected_python_requires == result["python_requires"]
def test_setup_reader_read_first_level_setup_call_with_variables(setup): def test_setup_reader_read_first_level_setup_call_with_variables(
setup: Callable[[str], str]
):
result = SetupReader.read_from_directory(setup("requests")) result = SetupReader.read_from_directory(setup("requests"))
expected_name = None expected_name = None
...@@ -71,7 +77,9 @@ def test_setup_reader_read_first_level_setup_call_with_variables(setup): ...@@ -71,7 +77,9 @@ def test_setup_reader_read_first_level_setup_call_with_variables(setup):
assert expected_python_requires == result["python_requires"] assert expected_python_requires == result["python_requires"]
def test_setup_reader_read_sub_level_setup_call_with_direct_types(setup): def test_setup_reader_read_sub_level_setup_call_with_direct_types(
setup: Callable[[str], str]
):
result = SetupReader.read_from_directory(setup("sqlalchemy")) result = SetupReader.read_from_directory(setup("sqlalchemy"))
expected_name = "SQLAlchemy" expected_name = "SQLAlchemy"
...@@ -95,7 +103,7 @@ def test_setup_reader_read_sub_level_setup_call_with_direct_types(setup): ...@@ -95,7 +103,7 @@ def test_setup_reader_read_sub_level_setup_call_with_direct_types(setup):
assert result["python_requires"] is None assert result["python_requires"] is None
def test_setup_reader_read_setup_cfg(setup): def test_setup_reader_read_setup_cfg(setup: Callable[[str], str]):
result = SetupReader.read_from_directory(setup("with-setup-cfg")) result = SetupReader.read_from_directory(setup("with-setup-cfg"))
expected_name = "with-setup-cfg" expected_name = "with-setup-cfg"
...@@ -114,12 +122,12 @@ def test_setup_reader_read_setup_cfg(setup): ...@@ -114,12 +122,12 @@ def test_setup_reader_read_setup_cfg(setup):
assert expected_python_requires == result["python_requires"] assert expected_python_requires == result["python_requires"]
def test_setup_reader_read_setup_cfg_with_attr(setup): def test_setup_reader_read_setup_cfg_with_attr(setup: Callable[[str], str]):
with pytest.raises(InvalidVersion): with pytest.raises(InvalidVersion):
SetupReader.read_from_directory(setup("with-setup-cfg-attr")) SetupReader.read_from_directory(setup("with-setup-cfg-attr"))
def test_setup_reader_read_setup_kwargs(setup): def test_setup_reader_read_setup_kwargs(setup: Callable[[str], str]):
result = SetupReader.read_from_directory(setup("pendulum")) result = SetupReader.read_from_directory(setup("pendulum"))
expected_name = "pendulum" expected_name = "pendulum"
...@@ -135,7 +143,7 @@ def test_setup_reader_read_setup_kwargs(setup): ...@@ -135,7 +143,7 @@ def test_setup_reader_read_setup_kwargs(setup):
assert expected_python_requires == result["python_requires"] assert expected_python_requires == result["python_requires"]
def test_setup_reader_read_setup_call_in_main(setup): def test_setup_reader_read_setup_call_in_main(setup: Callable[[str], str]):
result = SetupReader.read_from_directory(setup("pyyaml")) result = SetupReader.read_from_directory(setup("pyyaml"))
expected_name = "PyYAML" expected_name = "PyYAML"
...@@ -151,7 +159,7 @@ def test_setup_reader_read_setup_call_in_main(setup): ...@@ -151,7 +159,7 @@ def test_setup_reader_read_setup_call_in_main(setup):
assert expected_python_requires == result["python_requires"] assert expected_python_requires == result["python_requires"]
def test_setup_reader_read_extras_require_with_variables(setup): def test_setup_reader_read_extras_require_with_variables(setup: Callable[[str], str]):
result = SetupReader.read_from_directory(setup("extras_require_with_vars")) result = SetupReader.read_from_directory(setup("extras_require_with_vars"))
expected_name = "extras_require_with_vars" expected_name = "extras_require_with_vars"
...@@ -167,7 +175,7 @@ def test_setup_reader_read_extras_require_with_variables(setup): ...@@ -167,7 +175,7 @@ def test_setup_reader_read_extras_require_with_variables(setup):
assert expected_python_requires == result["python_requires"] assert expected_python_requires == result["python_requires"]
def test_setup_reader_setuptools(setup): def test_setup_reader_setuptools(setup: Callable[[str], str]):
result = SetupReader.read_from_directory(setup("setuptools_setup")) result = SetupReader.read_from_directory(setup("setuptools_setup"))
expected_name = "my_package" expected_name = "my_package"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment