Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul for stable #98

Merged
merged 19 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/scripts/setup-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ poetry --version --no-ansi;
poetry run pip --version;

poetry install \
--extras poetry \
--quiet \
--remove-untracked \
--no-ansi;
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ jobs:
strategy:
matrix:
python:
- version: "3.7"
toxenv: py37
- version: "3.8"
toxenv: py38
- version: "3.9"
Expand All @@ -22,6 +20,8 @@ jobs:
toxenv: py310
- version: "3.11"
toxenv: py311
- version: "3.12"
toxenv: py312
fail-fast: true
steps:
- name: Checkout
Expand Down
7 changes: 4 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ repos:

- id: reorder-python-imports
name: reorder-python-imports
entry: reorder-python-imports
entry: isort
language: system
args:
- "--unclassifiable-application-module=tox_poetry_installer"
require_serial: true
types:
- python
args:
- "--filter-files"

- id: black
name: black
Expand Down
1 change: 0 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
# --disable=W"
disable=logging-fstring-interpolation
,logging-format-interpolation
,bad-continuation
,line-too-long
,ungrouped-imports
,typecheck
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ error will be set to one of the "Status" values below to indicate what the error
| `LockedDepNotFoundError` | Indicates that an item specified in the `locked_deps` config option does not match the name of a package in the Poetry lockfile. |
| `LockedDepsRequiredError` | Indicates that a test environment with the `require_locked_deps` config option set to `true` also specified unlocked dependencies using the [`deps`](https://tox.readthedocs.io/en/latest/config.html#conf-deps) config option. |
| `PoetryNotInstalledError` | Indicates that the `poetry` module could not be imported under the current runtime environment, and `require_poetry = true` was specified. |
| `RequiresUnsafeDepError` | Indicates that the package-under-test depends on a package that Poetry has classified as unsafe and cannot be installed. |

> ℹ️ **Note:** One or more of these errors can be caused by the `pyproject.toml` being out
> of sync with the Poetry lockfile. If this is the case, than a warning will be logged
Expand Down
2,775 changes: 1,186 additions & 1,589 deletions poetry.lock

Large diffs are not rendered by default.

51 changes: 26 additions & 25 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,45 +23,46 @@ classifiers = [
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
]

[tool.poetry.plugins.tox]
poetry_installer = "tox_poetry_installer"

[tool.poetry.extras]
poetry = ["poetry", "cleo"]

[tool.poetry.dependencies]
python = "^3.7"
cleo = {version = ">=1.0,<3.0", optional = true}
poetry = {version = "^1.5.0", optional = true}
python = "^3.8"
cleo = ">=1.0,<3.0"
poetry = "^1.5.0"
poetry-core = "^1.1.0"
tox = "^4"
tox = "^4.1"

[tool.poetry.group.dev.dependencies]
bandit = "^1.6.2"
black = "^22.3.0"
blacken-docs = "^1.8.0"
ipython = {version = "^8.10.1", python = "^3.8"}
mdformat = "^0.7"
mdformat-gfm = "^0.3"
mypy = "^0.930"
pre-commit = "^2.7.1"
pre-commit-hooks = "^3.3.0"
pylint = "^2.13.0"
pytest = "^6.0.2"
pytest-cov = "^2.10.1"
reorder-python-imports = "^2.3.5"
safety = "^2.2.0"
toml = "^0.10.1"
tox = "^4"
types-toml = "^0.10.1"
bandit = {version = "^1.7.7", python = "^3.10"}
black = {version = "^24.3.0", python = "^3.10"}
blacken-docs = {version = "^1.18.0", python = "^3.10"}
ipython = {version = "^8.10.1", python = "^3.10"}
isort = {version = "^5.13.2", python = "^3.10"}
mdformat = {version = "^0.7", python = "^3.10"}
mdformat-gfm = {version = "^0.3", python = "^3.10"}
mypy = {version = "^1.11.1", python = "^3.10"}
pre-commit = {version = "^3.8.0", python = "^3.10"}
pre-commit-hooks = {version = "^4.6.0", python = "^3.10"}
pylint = {version = "^3.2.6", python = "^3.10"}
pytest = {version = "^8.3.2", python = "^3.10"}
pytest-cov = {version = "^5.0.0", python = "^3.10"}
toml = {version = "^0.10.1", python = "^3.10"}
tox = "^4.1"
types-toml = {version = "^0.10.1", python = "^3.10"}

[tool.isort]
profile = "black"
force_single_line = "true"
lines_after_imports = 2

[build-system]
requires = ["poetry-core>=1.1.0"]
Expand Down
20 changes: 13 additions & 7 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# pylint: disable=missing-module-docstring, missing-function-docstring, unused-argument, too-few-public-methods
# pylint: disable=missing-module-docstring,missing-function-docstring,unused-argument,too-few-public-methods,protected-access
import time
from pathlib import Path
from typing import List

import poetry.factory
import poetry.installation.executor
import poetry.installation.operations.operation
import poetry.utils.env
import pytest
import tox.tox_env.python.virtual_env.runner
from poetry.installation.operations.operation import Operation

from tox_poetry_installer import utilities
import tox_poetry_installer.hooks._tox_on_install_helpers


TEST_PROJECT_PATH = Path(__file__).parent.resolve() / "test-project"
Expand Down Expand Up @@ -40,14 +40,20 @@ class MockExecutor:
def __init__(self, env: MockVirtualEnv, **kwargs):
self.env = env

def execute(self, operations: List[Operation]):
def execute(
self, operations: List[poetry.installation.operations.operation.Operation]
):
self.env.installed.extend([operation.package for operation in operations])
time.sleep(1)


@pytest.fixture
def mock_venv(monkeypatch):
monkeypatch.setattr(utilities, "convert_virtualenv", lambda venv: venv)
monkeypatch.setattr(
tox_poetry_installer.hooks._tox_on_install_helpers,
"convert_virtualenv",
lambda venv: venv,
)
monkeypatch.setattr(poetry.installation.executor, "Executor", MockExecutor)
monkeypatch.setattr(
tox.tox_env.python.virtual_env.runner, "VirtualEnvRunner", MockVirtualEnv
Expand All @@ -57,9 +63,9 @@ def mock_venv(monkeypatch):

@pytest.fixture(scope="function")
def mock_poetry_factory(monkeypatch):
pypoetry = poetry.factory.Factory().create_poetry(cwd=TEST_PROJECT_PATH)
project = poetry.factory.Factory().create_poetry(cwd=TEST_PROJECT_PATH)

def mock_factory(*args, **kwargs):
return pypoetry
return project

monkeypatch.setattr(poetry.factory.Factory, "create_poetry", mock_factory)
47 changes: 27 additions & 20 deletions tests/test_installer.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
# pylint: disable=missing-module-docstring, redefined-outer-name, unused-argument, wrong-import-order, unused-import
# pylint: disable=missing-module-docstring,redefined-outer-name,unused-argument,unused-import,protected-access
import time
from unittest import mock

import poetry.factory
import poetry.installation.executor
import pytest
import tox.tox_env.python.virtual_env.runner
from poetry.factory import Factory

import tox_poetry_installer.hooks._tox_on_install_helpers

from .fixtures import mock_poetry_factory
from .fixtures import mock_venv
from tox_poetry_installer import installer
from tox_poetry_installer import utilities


def test_deduplication(mock_venv, mock_poetry_factory):
"""Test that the installer does not install duplicate dependencies"""
poetry = Factory().create_poetry(None)
packages: utilities.PackageMap = {
item.name: item for item in poetry.locker.locked_repository().packages
project = poetry.factory.Factory().create_poetry(None)
packages: tox_poetry_installer.hooks._tox_on_install_helpers.PackageMap = {
item.name: item for item in project.locker.locked_repository().packages
}

venv = tox.tox_env.python.virtual_env.runner.VirtualEnvRunner()
to_install = [packages["toml"], packages["toml"]]

installer.install(poetry, venv, to_install)
tox_poetry_installer.hooks._tox_on_install_helpers.install_package(
project, venv, to_install
)

assert len(set(to_install)) == len(venv.installed) # pylint: disable=no-member


def test_parallelization(mock_venv, mock_poetry_factory):
"""Test that behavior is consistent between parallel and non-parallel usage"""
poetry = Factory().create_poetry(None)
packages: utilities.PackageMap = {
item.name: item for item in poetry.locker.locked_repository().packages
project = poetry.factory.Factory().create_poetry(None)
packages: tox_poetry_installer.hooks._tox_on_install_helpers.PackageMap = {
item.name: item for item in project.locker.locked_repository().packages
}

to_install = [
Expand All @@ -45,12 +48,16 @@ def test_parallelization(mock_venv, mock_poetry_factory):

venv_sequential = tox.tox_env.python.virtual_env.runner.VirtualEnvRunner()
start_sequential = time.time()
installer.install(poetry, venv_sequential, to_install, 0)
tox_poetry_installer.hooks._tox_on_install_helpers.install_package(
project, venv_sequential, to_install, 0
)
sequential = time.time() - start_sequential

venv_parallel = tox.tox_env.python.virtual_env.runner.VirtualEnvRunner()
start_parallel = time.time()
installer.install(poetry, venv_parallel, to_install, 5)
tox_poetry_installer.hooks._tox_on_install_helpers.install_package(
project, venv_parallel, to_install, 5
)
parallel = time.time() - start_parallel

# The mock delay during package install is static (one second) so these values should all
Expand All @@ -69,22 +76,22 @@ def test_propagates_exceptions_during_installation(

Regression test for https://github.com/enpaul/tox-poetry-installer/issues/86
"""
from tox_poetry_installer import _poetry # pylint: disable=import-outside-toplevel

poetry = Factory().create_poetry(None)
packages: utilities.PackageMap = {
item.name: item for item in poetry.locker.locked_repository().packages
project = poetry.factory.Factory().create_poetry(None)
packages: tox_poetry_installer.hooks._tox_on_install_helpers.PackageMap = {
item.name: item for item in project.locker.locked_repository().packages
}
to_install = [packages["toml"]]
venv = tox.tox_env.python.virtual_env.runner.VirtualEnvRunner()
fake_exception = ValueError("my testing exception")

with mock.patch.object(
_poetry,
poetry.installation.executor,
"Executor",
**{"return_value.execute.side_effect": fake_exception},
):
with pytest.raises(ValueError) as exc_info:
installer.install(poetry, venv, to_install, num_threads)
tox_poetry_installer.hooks._tox_on_install_helpers.install_package(
project, venv, to_install, num_threads
)

assert exc_info.value is fake_exception
1 change: 1 addition & 0 deletions tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
The next best thing to having one source of truth is having a way to ensure all of your
sources of truth agree with each other.
"""

from pathlib import Path

import toml
Expand Down
46 changes: 23 additions & 23 deletions tests/test_transients.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
# pylint: disable=missing-module-docstring, redefined-outer-name, unused-argument, wrong-import-order, unused-import
# pylint: disable=missing-module-docstring,redefined-outer-name,unused-argument,unused-import,protected-access
import poetry.factory
import poetry.utils.env
import pytest
from poetry.puzzle.provider import Provider

from .fixtures import mock_poetry_factory
from .fixtures import mock_venv
from tox_poetry_installer import constants
import tox_poetry_installer.hooks._tox_on_install_helpers
from tox_poetry_installer import exceptions
from tox_poetry_installer import utilities


def test_exclude_unsafe():
"""Test that the unsafe packages are properly excluded

Also ensure that the internal constant matches the value from Poetry
"""
assert Provider.UNSAFE_PACKAGES == constants.UNSAFE_PACKAGES

for dep in constants.UNSAFE_PACKAGES:
assert not utilities.identify_transients(dep, {}, None)
from .fixtures import mock_poetry_factory
from .fixtures import mock_venv


def test_allow_missing():
"""Test that the ``allow_missing`` parameter works as expected"""
with pytest.raises(exceptions.LockedDepNotFoundError):
utilities.identify_transients("luke-skywalker", {}, None)
tox_poetry_installer.hooks._tox_on_install_helpers.identify_transients(
"luke-skywalker", {}, None
)

assert not utilities.identify_transients(
assert not tox_poetry_installer.hooks._tox_on_install_helpers.identify_transients(
"darth-vader", {}, None, allow_missing=["darth-vader"]
)

Expand All @@ -47,7 +37,9 @@ def test_exclude_pep508():
"=>foo",
]:
with pytest.raises(exceptions.LockedDepVersionConflictError):
utilities.identify_transients(version, {}, None)
tox_poetry_installer.hooks._tox_on_install_helpers.identify_transients(
version, {}, None
)


def test_functional(mock_poetry_factory, mock_venv):
Expand All @@ -56,8 +48,10 @@ def test_functional(mock_poetry_factory, mock_venv):
Trivially test that it resolves dependencies properly and that the parent package
is always the last in the returned list.
"""
pypoetry = poetry.factory.Factory().create_poetry(None)
packages = utilities.build_package_map(pypoetry)
project = poetry.factory.Factory().create_poetry(None)
packages = tox_poetry_installer.hooks._tox_on_install_helpers.build_package_map(
project
)
venv = poetry.utils.env.VirtualEnv() # pylint: disable=no-value-for-parameter

requests_requires = [
Expand All @@ -68,12 +62,18 @@ def test_functional(mock_poetry_factory, mock_venv):
packages["requests"][0],
]

transients = utilities.identify_transients("requests", packages, venv)
transients = tox_poetry_installer.hooks._tox_on_install_helpers.identify_transients(
"requests", packages, venv
)

assert all((item in requests_requires) for item in transients)
assert all((item in transients) for item in requests_requires)

for package in [packages["requests"][0], packages["tox"][0], packages["flask"][0]]:
transients = utilities.identify_transients(package.name, packages, venv)
transients = (
tox_poetry_installer.hooks._tox_on_install_helpers.identify_transients(
package.name, packages, venv
)
)
assert transients[-1] == package
assert len(transients) == len(set(transients))
Loading
Loading