Skip to content

Commit

Permalink
Replace container_from_pytest_param with container_and_marks_from_pyt…
Browse files Browse the repository at this point in the history
…est_param

- deprecate container_from_pytest_param
- replace it internally with container_and_marks_from_pytest_param

container_and_marks_from_pytest_param is more flexible as it encourages users to
not forget about marks when creating new containers from `pytest.param`
instances.
  • Loading branch information
dcermak committed Nov 2, 2023
1 parent af62fc3 commit 1622568
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ Next Release

Breaking changes:

- deprecate the function ``pytest_container.container_from_pytest_param``,
please use
:py:func:`~pytest_container.container.container_and_marks_from_pytest_param`
instead.


Improvements and new features:

Expand Down
16 changes: 15 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dataclasses = { version = ">=0.8", python = "< 3.7" }
typing-extensions = { version = ">=3.0", markers="python_version < '3.8'" }
cached-property = { version = "^1.5", markers="python_version < '3.8'" }
filelock = "^3.4"
deprecation = "^2.1"

[tool.poetry.dev-dependencies]
black = ">=21.9b0"
Expand All @@ -57,5 +58,5 @@ line-length = 79
strict = true

[[tool.mypy.overrides]]
module = "testinfra"
module = "testinfra,deprecation"
ignore_missing_imports = true
1 change: 1 addition & 0 deletions pytest_container/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .build import GitRepositoryBuild
from .build import MultiStageBuild
from .container import Container
from .container import container_and_marks_from_pytest_param
from .container import container_from_pytest_param
from .container import container_to_pytest_param
from .container import DerivedContainer
Expand Down
12 changes: 7 additions & 5 deletions pytest_container/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from _pytest.config import Config
from _pytest.mark.structures import ParameterSet
from pytest_container.container import Container
from pytest_container.container import container_from_pytest_param
from pytest_container.container import container_and_marks_from_pytest_param
from pytest_container.container import DerivedContainer
from pytest_container.logging import _logger
from pytest_container.runtime import OciRuntimeBase
Expand Down Expand Up @@ -158,7 +158,9 @@ def containerfile(self) -> str:
**{
k: v
if isinstance(v, str)
else str(container_from_pytest_param(v)._build_tag)
else str(
container_and_marks_from_pytest_param(v)[0]._build_tag
)
for k, v in self.containers.items()
}
)
Expand All @@ -178,9 +180,9 @@ def prepare_build(
_logger.debug("Preparing multistage build")
for _, container in self.containers.items():
if not isinstance(container, str):
container_from_pytest_param(container).prepare_container(
rootdir, extra_build_args
)
container_and_marks_from_pytest_param(container)[
0
].prepare_container(rootdir, extra_build_args)

dockerfile_dest = tmp_path / "Dockerfile"
with open(dockerfile_dest, "w", encoding="utf-8") as containerfile:
Expand Down
74 changes: 71 additions & 3 deletions pytest_container/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@
from typing import List
from typing import Optional
from typing import overload
from typing import Tuple
from typing import Type
from typing import Union
from uuid import uuid4

import deprecation
import pytest
import testinfra
from _pytest.mark.structures import MarkDecorator
from _pytest.mark.structures import ParameterSet
from _pytest.mark import ParameterSet
from filelock import FileLock
from pytest_container.inspect import ContainerHealth
from pytest_container.inspect import ContainerInspect
Expand All @@ -51,6 +52,13 @@
from pytest_container.runtime import get_selected_runtime
from pytest_container.runtime import OciRuntimeBase

if sys.version_info >= (3, 8):
from importlib import metadata
from typing import Literal
else:
import importlib_metadata as metadata
from typing_extensions import Literal


@enum.unique
class ImageFormat(enum.Enum):
Expand Down Expand Up @@ -853,7 +861,9 @@ def inspect(self) -> ContainerInspect:

def container_to_pytest_param(
container: ContainerBase,
marks: Optional[Union[Collection[MarkDecorator], MarkDecorator]] = None,
marks: Optional[
Union[Collection[pytest.MarkDecorator], pytest.MarkDecorator]
] = None,
) -> ParameterSet:
"""Converts a subclass of :py:class:`~pytest_container.container.ContainerBase`
(:py:class:`~pytest_container.container.Container` or
Expand All @@ -869,6 +879,64 @@ def container_to_pytest_param(
return pytest.param(container, marks=marks or [], id=str(container))


@overload
def container_and_marks_from_pytest_param(
param: Container,
) -> Tuple[Container, Literal[None]]:
...

Check warning on line 886 in pytest_container/container.py

View check run for this annotation

Codecov / codecov/patch

pytest_container/container.py#L886

Added line #L886 was not covered by tests


@overload
def container_and_marks_from_pytest_param(
param: DerivedContainer,
) -> Tuple[DerivedContainer, Literal[None]]:
...

Check warning on line 893 in pytest_container/container.py

View check run for this annotation

Codecov / codecov/patch

pytest_container/container.py#L893

Added line #L893 was not covered by tests


@overload
def container_and_marks_from_pytest_param(
param: ParameterSet,
) -> Tuple[
Union[Container, DerivedContainer],
Optional[Collection[Union[pytest.MarkDecorator, pytest.Mark]]],
]:
...

Check warning on line 903 in pytest_container/container.py

View check run for this annotation

Codecov / codecov/patch

pytest_container/container.py#L903

Added line #L903 was not covered by tests


def container_and_marks_from_pytest_param(
param: Union[ParameterSet, Container, DerivedContainer],
) -> Tuple[
Union[Container, DerivedContainer],
Optional[Collection[Union[pytest.MarkDecorator, pytest.Mark]]],
]:
"""Extracts the :py:class:`~pytest_container.container.Container` or
:py:class:`~pytest_container.container.DerivedContainer` and the
corresponding marks from a `pytest.param
<https://docs.pytest.org/en/stable/reference.html?#pytest.param>`_ and
returns both.
If ``param`` is either a :py:class:`~pytest_container.container.Container`
or a :py:class:`~pytest_container.container.DerivedContainer`, then param is
returned directly and the second return value is ``None``.
"""
if isinstance(param, (Container, DerivedContainer)):
return param, None

if len(param.values) > 0 and isinstance(
param.values[0], (Container, DerivedContainer)
):
return param.values[0], param.marks

raise ValueError(f"Invalid pytest.param values: {param.values}")


@deprecation.deprecated(
deprecated_in="0.4.0",
removed_in="0.5.0",
current_version=metadata.version("pytest_container"),
details="use container_and_marks_from_pytest_param instead",
) # type: ignore
def container_from_pytest_param(
param: Union[ParameterSet, Container, DerivedContainer],
) -> Union[Container, DerivedContainer]:
Expand Down
12 changes: 6 additions & 6 deletions pytest_container/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from typing import Callable
from typing import Generator

from pytest_container.container import container_from_pytest_param
from pytest_container.container import container_and_marks_from_pytest_param
from pytest_container.container import ContainerData
from pytest_container.container import ContainerLauncher
from pytest_container.helpers import get_extra_build_args
Expand Down Expand Up @@ -76,12 +76,12 @@ def fixture(
pytest_generate_tests.
"""

launch_data = container_from_pytest_param(request.param)
_logger.debug("Requesting the container %s", str(launch_data))
container, _ = container_and_marks_from_pytest_param(request.param)
_logger.debug("Requesting the container %s", str(container))

if scope == "session" and launch_data.singleton:
if scope == "session" and container.singleton:
raise RuntimeError(
f"A singleton container ({launch_data}) cannot be used in a session level fixture"
f"A singleton container ({container}) cannot be used in a session level fixture"
)

add_labels = [
Expand All @@ -100,7 +100,7 @@ def fixture(
pass

with ContainerLauncher(
container=launch_data,
container=container,
container_runtime=container_runtime,
rootdir=pytestconfig.rootpath,
extra_build_args=get_extra_build_args(pytestconfig),
Expand Down
28 changes: 28 additions & 0 deletions tests/test_pytest_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pytest_container import get_extra_build_args
from pytest_container import MultiStageBuild
from pytest_container import OciRuntimeBase
from pytest_container.container import container_and_marks_from_pytest_param
from pytest_container.container import ContainerData
from pytest_container.pod import Pod
from pytest_container.pod import pod_from_pytest_param
Expand Down Expand Up @@ -117,6 +118,33 @@ def test_container_from_pytest_param() -> None:
assert "(16, 45)" in str(val_err_ctx.value)


def test_container_and_marks_from_pytest_param() -> None:
cont, marks = container_and_marks_from_pytest_param(
container_to_pytest_param(LEAP)
)
assert cont == LEAP and not marks

cont, marks = container_and_marks_from_pytest_param(
pytest.param(LEAP, 1, "a")
)
assert cont == LEAP and not marks

assert container_and_marks_from_pytest_param(LEAP) == (LEAP, None)

derived = DerivedContainer(base=LEAP, containerfile="ENV foo=bar")
cont, marks = container_and_marks_from_pytest_param(
container_to_pytest_param(derived)
)
assert cont == derived and not marks

assert container_and_marks_from_pytest_param(derived) == (derived, None)

with pytest.raises(ValueError) as val_err_ctx:
container_and_marks_from_pytest_param(pytest.param(16, 45))
assert "Invalid pytest.param values" in str(val_err_ctx.value)
assert "(16, 45)" in str(val_err_ctx.value)


@pytest.mark.parametrize(
"param,expected_pod",
[(TEST_POD, TEST_POD), (pytest.param(TEST_POD), TEST_POD)],
Expand Down

0 comments on commit 1622568

Please sign in to comment.