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 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/"}}})
......
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)
......
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