diff --git a/examples/django/requirements.txt b/examples/django/requirements.txt index d5c2459ec..98a37508e 100644 --- a/examples/django/requirements.txt +++ b/examples/django/requirements.txt @@ -2,5 +2,4 @@ sqlalchemy>=1.2.18 django>=2.2.1 pytest-django>=4.7.0 pytest-xdist>=3.5.0 -pytest-celery~=1.0.0b -celery[redis,pymemcache]>=5.0.0 \ No newline at end of file +pytest-celery[all]@git+https://github.com/Katz-Consulting-Group/pytest-celery.git@bugfix diff --git a/examples/myutils/requirements.txt b/examples/myutils/requirements.txt index 347d653e6..b8a10941e 100644 --- a/examples/myutils/requirements.txt +++ b/examples/myutils/requirements.txt @@ -1,4 +1,3 @@ pytest>=7.4.4 pytest-xdist>=3.5.0 -pytest-celery~=1.0.0b -celery[redis,pymemcache]>=5.0.0 +pytest-celery[all]@git+https://github.com/Katz-Consulting-Group/pytest-celery.git@bugfix diff --git a/examples/myworker/requirements.txt b/examples/myworker/requirements.txt index 347d653e6..b8a10941e 100644 --- a/examples/myworker/requirements.txt +++ b/examples/myworker/requirements.txt @@ -1,4 +1,3 @@ pytest>=7.4.4 pytest-xdist>=3.5.0 -pytest-celery~=1.0.0b -celery[redis,pymemcache]>=5.0.0 +pytest-celery[all]@git+https://github.com/Katz-Consulting-Group/pytest-celery.git@bugfix diff --git a/examples/rabbitmq_management/requirements.txt b/examples/rabbitmq_management/requirements.txt index 678461d85..b8a10941e 100644 --- a/examples/rabbitmq_management/requirements.txt +++ b/examples/rabbitmq_management/requirements.txt @@ -1,4 +1,3 @@ pytest>=7.4.4 pytest-xdist>=3.5.0 -pytest-celery~=1.0.0b -celery[redis,pymemcache]>=5.0.0 \ No newline at end of file +pytest-celery[all]@git+https://github.com/Katz-Consulting-Group/pytest-celery.git@bugfix diff --git a/examples/range/requirements.txt b/examples/range/requirements.txt index 4f2602a57..d893cd6b2 100644 --- a/examples/range/requirements.txt +++ b/examples/range/requirements.txt @@ -1,5 +1,4 @@ pytest>=7.4.4 pytest-xdist>=3.5.0 pytest-subtests>=0.11.0 -pytest-celery~=1.0.0b -celery[redis,pymemcache]>=5.0.0 \ No newline at end of file +pytest-celery[all]@git+https://github.com/Katz-Consulting-Group/pytest-celery.git@bugfix diff --git a/poetry.lock b/poetry.lock index 84f22b617..d862fc577 100644 --- a/poetry.lock +++ b/poetry.lock @@ -26,7 +26,7 @@ files = [ name = "amqp" version = "5.2.0" description = "Low-level AMQP client for Python (fork of amqplib)." -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, @@ -54,7 +54,7 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, @@ -131,7 +131,7 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] name = "backports-zoneinfo" version = "0.2.1" description = "Backport of the standard library zoneinfo module" -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, @@ -162,7 +162,7 @@ tzdata = ["tzdata"] name = "billiard" version = "4.2.0" description = "Python multiprocessing fork with improvements and bugfixes" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d"}, @@ -275,7 +275,7 @@ files = [ name = "celery" version = "5.3.6" description = "Distributed Task Queue." -optional = false +optional = true python-versions = ">=3.8" files = [ {file = "celery-5.3.6-py3-none-any.whl", hash = "sha256:9da4ea0118d232ce97dff5ed4974587fb1c0ff5c10042eb15278487cdd27d1af"}, @@ -291,8 +291,6 @@ click-plugins = ">=1.1.1" click-repl = ">=0.2.0" kombu = ">=5.3.4,<6.0" python-dateutil = ">=2.8.2" -python-memcached = {version = "1.59", optional = true, markers = "extra == \"pymemcache\""} -redis = {version = ">=4.5.2,<4.5.5 || >4.5.5,<6.0.0", optional = true, markers = "extra == \"redis\""} tzdata = ">=2022.7" vine = ">=5.1.0,<6.0" @@ -572,7 +570,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "click-didyoumean" version = "0.3.0" description = "Enables git-like *did-you-mean* feature in click" -optional = false +optional = true python-versions = ">=3.6.2,<4.0.0" files = [ {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"}, @@ -586,7 +584,7 @@ click = ">=7" name = "click-plugins" version = "1.1.1" description = "An extension module for click to enable registering CLI commands via setuptools entry-points." -optional = false +optional = true python-versions = "*" files = [ {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, @@ -603,7 +601,7 @@ dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] name = "click-repl" version = "0.3.0" description = "REPL plugin for Click" -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, @@ -1178,7 +1176,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-ena name = "kombu" version = "5.3.5" description = "Messaging library for Python." -optional = false +optional = true python-versions = ">=3.8" files = [ {file = "kombu-5.3.5-py3-none-any.whl", hash = "sha256:0eac1bbb464afe6fb0924b21bf79460416d25d8abc52546d4f16cad94f789488"}, @@ -1632,7 +1630,7 @@ virtualenv = ">=20.10.0" name = "prompt-toolkit" version = "3.0.43" description = "Library for building powerful interactive command lines in Python" -optional = false +optional = true python-versions = ">=3.7.0" files = [ {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, @@ -2033,7 +2031,7 @@ testing = ["filelock"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, @@ -2047,7 +2045,7 @@ six = ">=1.5" name = "python-memcached" version = "1.59" description = "Pure python memcached client" -optional = false +optional = true python-versions = "*" files = [ {file = "python-memcached-1.59.tar.gz", hash = "sha256:a2e28637be13ee0bf1a8b6843e7490f9456fd3f2a4cb60471733c7b5d5557e4f"}, @@ -2268,7 +2266,7 @@ full = ["numpy"] name = "redis" version = "5.0.2" description = "Python client for Redis database and key-value store" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "redis-5.0.2-py3-none-any.whl", hash = "sha256:4caa8e1fcb6f3c0ef28dba99535101d80934b7d4cd541bbb47f4a3826ee472d1"}, @@ -2922,7 +2920,7 @@ files = [ name = "tzdata" version = "2024.1" description = "Provider of IANA time zone data" -optional = false +optional = true python-versions = ">=2" files = [ {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, @@ -2950,7 +2948,7 @@ zstd = ["zstandard (>=0.18.0)"] name = "vine" version = "5.1.0" description = "Python promises." -optional = false +optional = true python-versions = ">=3.6" files = [ {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, @@ -2981,7 +2979,7 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "wcwidth" version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" -optional = false +optional = true python-versions = "*" files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, @@ -3076,7 +3074,13 @@ files = [ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +[extras] +all = ["celery", "python-memcached", "redis"] +celery = ["celery"] +memcached = ["python-memcached"] +redis = ["redis"] + [metadata] lock-version = "2.0" python-versions = ">= 3.8,<4.0" -content-hash = "3fada5411477ce7c77a50f589addba6655625c256d5e2b614706f45d59786b9c" +content-hash = "da931da2f9a734de5336db18f26d8bc3f86889bae7472a2cd7ae55b852daa7a4" diff --git a/pyproject.toml b/pyproject.toml index 92f90d41d..0aa44c6fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,9 @@ search = ':Version: {current_version}' replace = ':Version: {new_version}' [tool.poetry.dependencies] -celery = { version = "^5.0.0", extras = ["redis", "pymemcache"] } +celery = { version = "*", optional = true } +redis = { version = "*", optional = true } +python-memcached = { version = "*", optional = true } python = ">= 3.8,<4.0" retry = "^0.9.2" pytest-docker-tools = "^3.1.3" @@ -80,6 +82,12 @@ docker = "^7.0.0" psutil = "^5.9.7" setuptools = "^69.1.0" +[tool.poetry.extras] +all = ["celery", "redis", "python-memcached"] +celery = ["celery"] +redis = ["redis"] +memcached = ["python-memcached"] + [tool.poetry.group.dev] [tool.poetry.group.dev.dependencies] diff --git a/src/pytest_celery/__init__.py b/src/pytest_celery/__init__.py index 75183b8a2..c51b96093 100644 --- a/src/pytest_celery/__init__.py +++ b/src/pytest_celery/__init__.py @@ -13,34 +13,104 @@ import re from collections import namedtuple -from pytest_celery.api.backend import * -from pytest_celery.api.base import * -from pytest_celery.api.broker import * -from pytest_celery.api.container import * -from pytest_celery.api.setup import * -from pytest_celery.api.worker import * +from pytest_celery.api.backend import CeleryBackendCluster +from pytest_celery.api.backend import CeleryTestBackend +from pytest_celery.api.base import CeleryTestCluster +from pytest_celery.api.base import CeleryTestNode +from pytest_celery.api.broker import CeleryBrokerCluster +from pytest_celery.api.broker import CeleryTestBroker +from pytest_celery.api.container import CeleryTestContainer +from pytest_celery.api.setup import CeleryTestSetup +from pytest_celery.api.worker import CeleryTestWorker +from pytest_celery.api.worker import CeleryWorkerCluster from pytest_celery.defaults import * -from pytest_celery.fixtures.backend import * -from pytest_celery.fixtures.broker import * -from pytest_celery.fixtures.setup import * -from pytest_celery.fixtures.worker import * -from pytest_celery.vendors.memcached.api import * -from pytest_celery.vendors.memcached.container import * -from pytest_celery.vendors.memcached.fixtures import * -from pytest_celery.vendors.rabbitmq.api import * -from pytest_celery.vendors.rabbitmq.container import * -from pytest_celery.vendors.rabbitmq.fixtures import * -from pytest_celery.vendors.redis.backend.api import * -from pytest_celery.vendors.redis.backend.fixtures import * -from pytest_celery.vendors.redis.broker.api import * -from pytest_celery.vendors.redis.broker.fixtures import * -from pytest_celery.vendors.redis.container import * -from pytest_celery.vendors.worker.container import * -from pytest_celery.vendors.worker.content import app -from pytest_celery.vendors.worker.content import utils -from pytest_celery.vendors.worker.fixtures import * -from pytest_celery.vendors.worker.tasks import * -from pytest_celery.vendors.worker.volume import * +from pytest_celery.fixtures.backend import celery_backend +from pytest_celery.fixtures.backend import celery_backend_cluster +from pytest_celery.fixtures.backend import celery_backend_cluster_config +from pytest_celery.fixtures.broker import celery_broker +from pytest_celery.fixtures.broker import celery_broker_cluster +from pytest_celery.fixtures.broker import celery_broker_cluster_config +from pytest_celery.fixtures.setup import celery_setup +from pytest_celery.fixtures.setup import celery_setup_app +from pytest_celery.fixtures.setup import celery_setup_cls +from pytest_celery.fixtures.setup import celery_setup_config +from pytest_celery.fixtures.setup import celery_setup_name +from pytest_celery.fixtures.worker import celery_worker +from pytest_celery.fixtures.worker import celery_worker_cluster +from pytest_celery.fixtures.worker import celery_worker_cluster_config +from pytest_celery.vendors import _is_vendor_installed + +if _is_vendor_installed("memcached"): + from pytest_celery.vendors.memcached.api import MemcachedTestBackend + from pytest_celery.vendors.memcached.container import MemcachedContainer + from pytest_celery.vendors.memcached.defaults import * + from pytest_celery.vendors.memcached.fixtures import celery_memcached_backend + from pytest_celery.vendors.memcached.fixtures import default_memcached_backend + from pytest_celery.vendors.memcached.fixtures import default_memcached_backend_cls + from pytest_celery.vendors.memcached.fixtures import default_memcached_backend_env + from pytest_celery.vendors.memcached.fixtures import default_memcached_backend_image + from pytest_celery.vendors.memcached.fixtures import default_memcached_backend_ports + +if _is_vendor_installed("rabbitmq"): + from pytest_celery.vendors.rabbitmq.api import RabbitMQTestBroker + from pytest_celery.vendors.rabbitmq.container import RabbitMQContainer + from pytest_celery.vendors.rabbitmq.defaults import * + from pytest_celery.vendors.rabbitmq.fixtures import celery_rabbitmq_broker + from pytest_celery.vendors.rabbitmq.fixtures import default_rabbitmq_broker + from pytest_celery.vendors.rabbitmq.fixtures import default_rabbitmq_broker_cls + from pytest_celery.vendors.rabbitmq.fixtures import default_rabbitmq_broker_env + from pytest_celery.vendors.rabbitmq.fixtures import default_rabbitmq_broker_image + from pytest_celery.vendors.rabbitmq.fixtures import default_rabbitmq_broker_ports + +if _is_vendor_installed("redis"): + from pytest_celery.vendors.redis.backend.api import RedisTestBackend + from pytest_celery.vendors.redis.backend.defaults import * + from pytest_celery.vendors.redis.backend.fixtures import celery_redis_backend + from pytest_celery.vendors.redis.backend.fixtures import default_redis_backend + from pytest_celery.vendors.redis.backend.fixtures import default_redis_backend_cls + from pytest_celery.vendors.redis.backend.fixtures import default_redis_backend_command + from pytest_celery.vendors.redis.backend.fixtures import default_redis_backend_env + from pytest_celery.vendors.redis.backend.fixtures import default_redis_backend_image + from pytest_celery.vendors.redis.backend.fixtures import default_redis_backend_ports + from pytest_celery.vendors.redis.broker.api import RedisTestBroker + from pytest_celery.vendors.redis.broker.defaults import * + from pytest_celery.vendors.redis.broker.fixtures import celery_redis_broker + from pytest_celery.vendors.redis.broker.fixtures import default_redis_broker + from pytest_celery.vendors.redis.broker.fixtures import default_redis_broker_cls + from pytest_celery.vendors.redis.broker.fixtures import default_redis_broker_command + from pytest_celery.vendors.redis.broker.fixtures import default_redis_broker_env + from pytest_celery.vendors.redis.broker.fixtures import default_redis_broker_image + from pytest_celery.vendors.redis.broker.fixtures import default_redis_broker_ports + from pytest_celery.vendors.redis.container import RedisContainer + from pytest_celery.vendors.redis.defaults import * + + +if _is_vendor_installed("worker"): + from pytest_celery.vendors.worker.container import CeleryWorkerContainer + from pytest_celery.vendors.worker.content import app + from pytest_celery.vendors.worker.content import utils + from pytest_celery.vendors.worker.fixtures import celery_base_worker_image + from pytest_celery.vendors.worker.fixtures import celery_setup_worker + from pytest_celery.vendors.worker.fixtures import default_worker_app + from pytest_celery.vendors.worker.fixtures import default_worker_app_module + from pytest_celery.vendors.worker.fixtures import default_worker_celery_log_level + from pytest_celery.vendors.worker.fixtures import default_worker_celery_version + from pytest_celery.vendors.worker.fixtures import default_worker_celery_worker_name + from pytest_celery.vendors.worker.fixtures import default_worker_celery_worker_queue + from pytest_celery.vendors.worker.fixtures import default_worker_cls + from pytest_celery.vendors.worker.fixtures import default_worker_command + from pytest_celery.vendors.worker.fixtures import default_worker_container + from pytest_celery.vendors.worker.fixtures import default_worker_container_cls + from pytest_celery.vendors.worker.fixtures import default_worker_container_session_cls + from pytest_celery.vendors.worker.fixtures import default_worker_env + from pytest_celery.vendors.worker.fixtures import default_worker_initial_content + from pytest_celery.vendors.worker.fixtures import default_worker_signals + from pytest_celery.vendors.worker.fixtures import default_worker_tasks + from pytest_celery.vendors.worker.fixtures import default_worker_utils_module + from pytest_celery.vendors.worker.fixtures import default_worker_volume + from pytest_celery.vendors.worker.tasks import ping + from pytest_celery.vendors.worker.volume import WorkerInitialContent + version_info_t = namedtuple( "version_info_t", diff --git a/src/pytest_celery/defaults.py b/src/pytest_celery/defaults.py index b67947a50..de93f67dc 100644 --- a/src/pytest_celery/defaults.py +++ b/src/pytest_celery/defaults.py @@ -4,6 +4,7 @@ from pytest_docker_tools import network +from pytest_celery.vendors import _is_vendor_installed from pytest_celery.vendors.memcached.defaults import CELERY_MEMCACHED_BACKEND from pytest_celery.vendors.memcached.defaults import * from pytest_celery.vendors.rabbitmq.defaults import CELERY_RABBITMQ_BROKER @@ -28,15 +29,24 @@ # will automatically add it to the parametrization of every (relevant) test IMPLICITLY! # Tests that do not rely on default parametrization will not be affected. + +ALL_CELERY_BACKENDS = [] +ALL_CELERY_BROKERS = [] + +if _is_vendor_installed("redis"): + ALL_CELERY_BACKENDS.append(CELERY_REDIS_BACKEND) + ALL_CELERY_BROKERS.append(CELERY_REDIS_BROKER) + +if _is_vendor_installed("rabbitmq"): + # Uses Kombu + ALL_CELERY_BROKERS.append(CELERY_RABBITMQ_BROKER) + +# Beta support at the moment, to be used manually +# if can_import_container('memcached'): +# ALL_CELERY_BACKENDS.append(CELERY_MEMCACHED_BACKEND) + +# Worker setup is assumed to be always available. ALL_CELERY_WORKERS = (CELERY_SETUP_WORKER,) -ALL_CELERY_BACKENDS = ( - CELERY_REDIS_BACKEND, - # CELERY_MEMCACHED_BACKEND, # Beta support at the moment, to be used manually -) -ALL_CELERY_BROKERS = ( - CELERY_REDIS_BROKER, - CELERY_RABBITMQ_BROKER, -) #################################################################################### # Fixtures diff --git a/src/pytest_celery/vendors/__init__.py b/src/pytest_celery/vendors/__init__.py index b08b47eba..fae2f50d4 100644 --- a/src/pytest_celery/vendors/__init__.py +++ b/src/pytest_celery/vendors/__init__.py @@ -1 +1,19 @@ """See :ref:`vendors`.""" + + +def _is_vendor_installed(vendor_name: str) -> bool: + """Check if a vendor is installed. + + Args: + vendor_name (str): Vendor package name. + + Returns: + bool: True if the vendor is installed, False otherwise. + """ + + try: + container_module = f"pytest_celery.vendors.{vendor_name}.container" + __import__(container_module) + return True + except ImportError: + return False