diff --git a/pyproject.toml b/pyproject.toml index 069be0d..c4b0616 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pytest-mock-resources" -version = "2.6.11" +version = "2.6.12" description = "A pytest plugin for easily instantiating reproducible mock resources." authors = [ "Omar Khan ", diff --git a/src/pytest_mock_resources/__init__.py b/src/pytest_mock_resources/__init__.py index 454c09e..2c9dfdd 100644 --- a/src/pytest_mock_resources/__init__.py +++ b/src/pytest_mock_resources/__init__.py @@ -1,6 +1,7 @@ from pytest_mock_resources.container import ( get_container, MongoConfig, + MotoConfig, MysqlConfig, PostgresConfig, RedisConfig, @@ -40,6 +41,7 @@ __all__ = [ "Credentials", "MongoConfig", + "MotoConfig", "MysqlConfig", "PostgresConfig", "RedisConfig", diff --git a/src/pytest_mock_resources/cli.py b/src/pytest_mock_resources/cli.py index 989598b..f3012fd 100644 --- a/src/pytest_mock_resources/cli.py +++ b/src/pytest_mock_resources/cli.py @@ -1,21 +1,10 @@ +from __future__ import annotations + import argparse -import enum -from typing import Dict, Type - -from pytest_mock_resources import ( - MongoConfig, - MysqlConfig, - PostgresConfig, - RedisConfig, - RedshiftConfig, -) + from pytest_mock_resources.config import DockerContainerConfig from pytest_mock_resources.container.base import container_name, get_container -postgres_image = PostgresConfig().image -mysql_image = MysqlConfig().image -mongo_image = MongoConfig().image - class StubPytestConfig: pmr_multiprocess_safe = False @@ -29,28 +18,6 @@ def getini(self, attr): return getattr(self, attr) -@enum.unique -class FixtureType(enum.Enum): - mongo = "mongo" - mysql = "mysql" - postgres = "postgres" - redis = "redis" - redshift = "redshift" - - @classmethod - def options(cls): - return ", ".join(fixture_base.value for fixture_base in cls) - - -_container_producers: Dict[FixtureType, Type[DockerContainerConfig]] = { - FixtureType.mongo: MongoConfig, - FixtureType.mysql: MysqlConfig, - FixtureType.postgres: PostgresConfig, - FixtureType.redis: RedisConfig, - FixtureType.redshift: RedshiftConfig, -} - - def main(): parser = create_parser() args = parser.parse_args() @@ -60,22 +27,27 @@ def main(): stop = args.stop start = not stop - for fixture_base in args.fixture_bases: - fixture_type = FixtureType(fixture_base) - execute(fixture_type, pytestconfig, start=start, stop=stop) + for fixture in args.fixtures: + if fixture not in DockerContainerConfig.subclasses: + valid_options = ", ".join(DockerContainerConfig.subclasses) + raise argparse.ArgumentError( + args.fixtures, + f"'{fixture}' invalid. Valid options include: {valid_options}", + ) + + execute(fixture, pytestconfig, start=start, stop=stop) def create_parser(): - # TODO: Add an options arg to DOWN a fixture_base's container parser = argparse.ArgumentParser( description="Premptively run docker containers to speed up initial startup of PMR Fixtures." ) parser.add_argument( - "fixture_bases", - metavar="Fixture Base", + "fixtures", + metavar="Fixture", type=str, nargs="+", - help="Available Fixture Bases: {}".format(FixtureType.options()), + help="Available Fixtures: {}".format(", ".join(DockerContainerConfig.subclasses)), ) parser.add_argument( "--stop", action="store_true", help="Stop previously started PMR containers" @@ -83,8 +55,8 @@ def create_parser(): return parser -def execute(fixture_type: FixtureType, pytestconfig: StubPytestConfig, start=True, stop=False): - config_cls = _container_producers[fixture_type] +def execute(fixture: str, pytestconfig: StubPytestConfig, start=True, stop=False): + config_cls = DockerContainerConfig.subclasses[fixture] config = config_cls() if start: @@ -95,11 +67,12 @@ def execute(fixture_type: FixtureType, pytestconfig: StubPytestConfig, start=Tru if stop: from python_on_whales import docker - name = container_name(fixture_type.value, config.port) + assert config.port + name = container_name(fixture, int(config.port)) try: container = docker.container.inspect(name) except Exception: - print(f"Failed to stop {fixture_type.value} container") + print(f"Failed to stop {fixture} container") else: container.kill() diff --git a/src/pytest_mock_resources/config.py b/src/pytest_mock_resources/config.py index ac9bea6..37976e6 100644 --- a/src/pytest_mock_resources/config.py +++ b/src/pytest_mock_resources/config.py @@ -1,7 +1,9 @@ +from __future__ import annotations + import functools import os import socket -from typing import Dict, Iterable +from typing import ClassVar, Dict, Iterable, Type _DOCKER_HOST = "host.docker.internal" @@ -49,9 +51,17 @@ def wrapper(self): class DockerContainerConfig: + name: ClassVar[str] + _fields: Iterable = {"image", "host", "port", "ci_port", "container_args"} _fields_defaults: Dict = {} + subclasses: Dict[str, Type[DockerContainerConfig]] = {} + + @classmethod + def __init_subclass__(cls): + DockerContainerConfig.subclasses[cls.name] = cls + def __init__(self, **kwargs): for field, value in kwargs.items(): if field not in self._fields: diff --git a/src/pytest_mock_resources/container/__init__.py b/src/pytest_mock_resources/container/__init__.py index 3558b9a..c2bd50f 100644 --- a/src/pytest_mock_resources/container/__init__.py +++ b/src/pytest_mock_resources/container/__init__.py @@ -1,7 +1,18 @@ -# flake8: noqa from pytest_mock_resources.container.base import get_container from pytest_mock_resources.container.mongo import MongoConfig +from pytest_mock_resources.container.moto import MotoConfig from pytest_mock_resources.container.mysql import MysqlConfig from pytest_mock_resources.container.postgres import PostgresConfig from pytest_mock_resources.container.redis import RedisConfig from pytest_mock_resources.container.redshift import RedshiftConfig + +__all__ = [ + "get_container", + "MongoConfig", + "MysqlConfig", + "PostgresConfig", + "PostgresConfig", + "RedisConfig", + "RedshiftConfig", + "MotoConfig", +] diff --git a/src/pytest_mock_resources/container/moto.py b/src/pytest_mock_resources/container/moto.py index cdd5439..900ae70 100644 --- a/src/pytest_mock_resources/container/moto.py +++ b/src/pytest_mock_resources/container/moto.py @@ -16,7 +16,8 @@ class MotoConfig(DockerContainerConfig): Defaults to :code:`5432`. """ - name = "postgres" + name = "moto" + _fields = {"image", "host", "port"} _fields_defaults = { "image": "motoserver/moto:4.0.6",